diff options
Diffstat (limited to 'devtools/client/shared/vendor/react-test-renderer.js')
-rw-r--r-- | devtools/client/shared/vendor/react-test-renderer.js | 10580 |
1 files changed, 10580 insertions, 0 deletions
diff --git a/devtools/client/shared/vendor/react-test-renderer.js b/devtools/client/shared/vendor/react-test-renderer.js new file mode 100644 index 0000000000..60f98c8a4f --- /dev/null +++ b/devtools/client/shared/vendor/react-test-renderer.js @@ -0,0 +1,10580 @@ +/** @license React v16.8.6 + * react-test-renderer.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require("resource://devtools/client/shared/vendor/react.js")) : + typeof define === 'function' && define.amd ? define(['devtools/client/shared/vendor/react'], factory) : + (global.ReactTestRenderer = factory(global.React)); +}(this, (function (React) { 'use strict'; + +/** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + +function invariant(condition, format, a, b, c, d, e, f) { + if (!condition) { + var error = void 0; + if (format === undefined) { + error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); + } else { + var args = [a, b, c, d, e, f]; + var argIndex = 0; + error = new Error(format.replace(/%s/g, function () { + return args[argIndex++]; + })); + error.name = 'Invariant Violation'; + } + + error.framesToPop = 1; // we don't care about invariant's own frame + throw error; + } +} + +// Relying on the `invariant()` implementation lets us +// preserve the format and params in the www builds. +/** + * WARNING: DO NOT manually require this module. + * This is a replacement for `invariant(...)` used by the error code system + * and will _only_ be required by the corresponding babel pass. + * It always throws. + */ +function reactProdInvariant(code) { + var argCount = arguments.length - 1; + var url = 'https://reactjs.org/docs/error-decoder.html?invariant=' + code; + for (var argIdx = 0; argIdx < argCount; argIdx++) { + url += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]); + } + // Rename it so that our build transform doesn't attempt + // to replace this invariant() call with reactProdInvariant(). + var i = invariant; + i(false, + // The error code is intentionally part of the message (and + // not the format argument) so that we could deduplicate + // different errors in logs based on the code. + 'Minified React error #' + code + '; visit %s ' + 'for the full message or use the non-minified dev environment ' + 'for full errors and additional helpful warnings. ', url); +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var _assign = ReactInternals.assign; + +/** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ + +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + + +function get(key) { + return key._reactInternalFiber; +} + + + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +// Prevent newer renderers from RTE when used with older react package versions. +// Current owner and dispatcher used to share the same ref, +// but PR #14548 split them out to better support the react-debug-tools package. +if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) { + ReactSharedInternals.ReactCurrentDispatcher = { + current: null + }; +} + +// The Symbol used to tag the ReactElement-like types. If there is no native Symbol +// nor polyfill, then a plain number is used for performance. +var hasSymbol = typeof Symbol === 'function' && Symbol.for; + +var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; +var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; +var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; +var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; +var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; +var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; +var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; + +var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; +var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; +var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; +var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; +var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; + +var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; +var FAUX_ITERATOR_SYMBOL = '@@iterator'; + +function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== 'object') { + return null; + } + var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === 'function') { + return maybeIterator; + } + return null; +} + +var Pending = 0; +var Resolved = 1; +var Rejected = 2; + +function refineResolvedLazyComponent(lazyComponent) { + return lazyComponent._status === Resolved ? lazyComponent._result : null; +} + +function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ''; + return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName); +} + +function getComponentName(type) { + if (type == null) { + // Host root, text node or just invalid type. + return null; + } + if (typeof type === 'function') { + return type.displayName || type.name || null; + } + if (typeof type === 'string') { + return type; + } + switch (type) { + case REACT_CONCURRENT_MODE_TYPE: + return 'ConcurrentMode'; + case REACT_FRAGMENT_TYPE: + return 'Fragment'; + case REACT_PORTAL_TYPE: + return 'Portal'; + case REACT_PROFILER_TYPE: + return 'Profiler'; + case REACT_STRICT_MODE_TYPE: + return 'StrictMode'; + case REACT_SUSPENSE_TYPE: + return 'Suspense'; + } + if (typeof type === 'object') { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + return 'Context.Consumer'; + case REACT_PROVIDER_TYPE: + return 'Context.Provider'; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, 'ForwardRef'); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_LAZY_TYPE: + { + var thenable = type; + var resolvedThenable = refineResolvedLazyComponent(thenable); + if (resolvedThenable) { + return getComponentName(resolvedThenable); + } + } + } + } + return null; +} + +var FunctionComponent = 0; +var ClassComponent = 1; +var IndeterminateComponent = 2; // Before we know whether it is function or class +var HostRoot = 3; // Root of a host tree. Could be nested inside another node. +var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. +var HostComponent = 5; +var HostText = 6; +var Fragment = 7; +var Mode = 8; +var ContextConsumer = 9; +var ContextProvider = 10; +var ForwardRef = 11; +var Profiler = 12; +var SuspenseComponent = 13; +var MemoComponent = 14; +var SimpleMemoComponent = 15; +var LazyComponent = 16; +var IncompleteClassComponent = 17; +var DehydratedSuspenseComponent = 18; + +// Don't change these two values. They're used by React Dev Tools. +var NoEffect = /* */0; +var PerformedWork = /* */1; + +// You can change the rest (and add more). +var Placement = /* */2; +var Update = /* */4; +var PlacementAndUpdate = /* */6; +var Deletion = /* */8; +var ContentReset = /* */16; +var Callback = /* */32; +var DidCapture = /* */64; +var Ref = /* */128; +var Snapshot = /* */256; +var Passive = /* */512; + +// Passive & Update & Callback & Ref & Snapshot +var LifecycleEffectMask = /* */932; + +// Union of all host effects +var HostEffectMask = /* */1023; + +var Incomplete = /* */1024; +var ShouldCapture = /* */2048; + +var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; + +var MOUNTING = 1; +var MOUNTED = 2; +var UNMOUNTED = 3; + +function isFiberMountedImpl(fiber) { + var node = fiber; + if (!fiber.alternate) { + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + while (node.return) { + node = node.return; + if ((node.effectTag & Placement) !== NoEffect) { + return MOUNTING; + } + } + } else { + while (node.return) { + node = node.return; + } + } + if (node.tag === HostRoot) { + // TODO: Check if this was a nested HostRoot when used with + // renderContainerIntoSubtree. + return MOUNTED; + } + // If we didn't hit the root, that means that we're in an disconnected tree + // that has been unmounted. + return UNMOUNTED; +} + +function isFiberMounted(fiber) { + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function isMounted(component) { + var fiber = get(component); + if (!fiber) { + return false; + } + return isFiberMountedImpl(fiber) === MOUNTED; +} + +function assertIsMounted(fiber) { + !(isFiberMountedImpl(fiber) === MOUNTED) ? reactProdInvariant('188') : void 0; +} + +function findCurrentFiberUsingSlowPath(fiber) { + var alternate = fiber.alternate; + if (!alternate) { + // If there is no alternate, then we only need to check if it is mounted. + var state = isFiberMountedImpl(fiber); + !(state !== UNMOUNTED) ? reactProdInvariant('188') : void 0; + if (state === MOUNTING) { + return null; + } + return fiber; + } + // If we have two possible branches, we'll walk backwards up to the root + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. + var a = fiber; + var b = alternate; + while (true) { + var parentA = a.return; + var parentB = parentA ? parentA.alternate : null; + if (!parentA || !parentB) { + // We're at the root. + break; + } + + // If both copies of the parent fiber point to the same child, we can + // assume that the child is current. This happens when we bailout on low + // priority: the bailed out fiber's child reuses the current child. + if (parentA.child === parentB.child) { + var child = parentA.child; + while (child) { + if (child === a) { + // We've determined that A is the current branch. + assertIsMounted(parentA); + return fiber; + } + if (child === b) { + // We've determined that B is the current branch. + assertIsMounted(parentA); + return alternate; + } + child = child.sibling; + } + // We should never have an alternate for any mounting node. So the only + // way this could possibly happen is if this was unmounted, if at all. + reactProdInvariant('188'); + } + + if (a.return !== b.return) { + // The return pointer of A and the return pointer of B point to different + // fibers. We assume that return pointers never criss-cross, so A must + // belong to the child set of A.return, and B must belong to the child + // set of B.return. + a = parentA; + b = parentB; + } else { + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set + var didFindChild = false; + var _child = parentA.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentA; + b = parentB; + break; + } + if (_child === b) { + didFindChild = true; + b = parentA; + a = parentB; + break; + } + _child = _child.sibling; + } + if (!didFindChild) { + // Search parent B's child set + _child = parentB.child; + while (_child) { + if (_child === a) { + didFindChild = true; + a = parentB; + b = parentA; + break; + } + if (_child === b) { + didFindChild = true; + b = parentB; + a = parentA; + break; + } + _child = _child.sibling; + } + !didFindChild ? reactProdInvariant('189') : void 0; + } + } + + !(a.alternate === b) ? reactProdInvariant('190') : void 0; + } + // If the root is not a host container, we're in a disconnected tree. I.e. + // unmounted. + !(a.tag === HostRoot) ? reactProdInvariant('188') : void 0; + if (a.stateNode.current === a) { + // We've determined that A is the current branch. + return fiber; + } + // Otherwise B has to be current branch. + return alternate; +} + +function findCurrentHostFiber(parent) { + var currentParent = findCurrentFiberUsingSlowPath(parent); + if (!currentParent) { + return null; + } + + // Next we'll drill down this component to find the first HostComponent/Text. + var node = currentParent; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + return node; + } else if (node.child) { + node.child.return = node; + node = node.child; + continue; + } + if (node === currentParent) { + return null; + } + while (!node.sibling) { + if (!node.return || node.return === currentParent) { + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + // Flow needs the return null here, but ESLint complains about it. + // eslint-disable-next-line no-unreachable + return null; +} + +// Current virtual time +var nowImplementation = function () { + return 0; +}; +var scheduledCallback = null; +var yieldedValues = []; + +var didStop = false; +var expectedNumberOfYields = -1; + +function scheduleDeferredCallback$1(callback, options) { + scheduledCallback = callback; + var fakeCallbackId = 0; + return fakeCallbackId; +} + +function cancelDeferredCallback$1(timeoutID) { + scheduledCallback = null; +} + +function setNowImplementation(implementation) { + nowImplementation = implementation; +} + +function shouldYield$1() { + if (expectedNumberOfYields !== -1 && yieldedValues.length >= expectedNumberOfYields) { + // We yielded at least as many values as expected. Stop rendering. + didStop = true; + return true; + } + // Keep rendering. + return false; +} + +function flushAll() { + yieldedValues = []; + while (scheduledCallback !== null) { + var cb = scheduledCallback; + scheduledCallback = null; + cb(); + } + var values = yieldedValues; + yieldedValues = []; + return values; +} + +function flushNumberOfYields(count) { + expectedNumberOfYields = count; + didStop = false; + yieldedValues = []; + try { + while (scheduledCallback !== null && !didStop) { + var cb = scheduledCallback; + scheduledCallback = null; + cb(); + } + return yieldedValues; + } finally { + expectedNumberOfYields = -1; + didStop = false; + yieldedValues = []; + } +} + +function yieldValue(value) { + yieldedValues.push(value); +} + +function clearYields() { + var values = yieldedValues; + yieldedValues = []; + return values; +} + +// Renderers that don't support persistence +// can re-export everything from this module. + +function shim() { + reactProdInvariant('270'); +} + +// Persistence (when unsupported) +var supportsPersistence = false; +var cloneInstance = shim; +var createContainerChildSet = shim; +var appendChildToContainerChildSet = shim; +var finalizeContainerChildren = shim; +var replaceContainerChildren = shim; +var cloneHiddenInstance = shim; +var cloneUnhiddenInstance = shim; +var createHiddenTextInstance = shim; + +// Renderers that don't support hydration +// can re-export everything from this module. + +function shim$1() { + reactProdInvariant('305'); +} + +// Hydration (when unsupported) + +var supportsHydration = false; +var canHydrateInstance = shim$1; +var canHydrateTextInstance = shim$1; +var canHydrateSuspenseInstance = shim$1; +var getNextHydratableSibling = shim$1; +var getFirstHydratableChild = shim$1; +var hydrateInstance = shim$1; +var hydrateTextInstance = shim$1; +var getNextHydratableInstanceAfterSuspenseInstance = shim$1; +var clearSuspenseBoundary = shim$1; +var clearSuspenseBoundaryFromContainer = shim$1; + +var NO_CONTEXT = {}; +var UPDATE_SIGNAL = {}; +function getPublicInstance(inst) { + switch (inst.tag) { + case 'INSTANCE': + var _createNodeMock = inst.rootContainerInstance.createNodeMock; + return _createNodeMock({ + type: inst.type, + props: inst.props + }); + default: + return inst; + } +} + +function appendChild(parentInstance, child) { + var index = parentInstance.children.indexOf(child); + if (index !== -1) { + parentInstance.children.splice(index, 1); + } + parentInstance.children.push(child); +} + +function insertBefore(parentInstance, child, beforeChild) { + var index = parentInstance.children.indexOf(child); + if (index !== -1) { + parentInstance.children.splice(index, 1); + } + var beforeIndex = parentInstance.children.indexOf(beforeChild); + parentInstance.children.splice(beforeIndex, 0, child); +} + +function removeChild(parentInstance, child) { + var index = parentInstance.children.indexOf(child); + parentInstance.children.splice(index, 1); +} + +function getRootHostContext(rootContainerInstance) { + return NO_CONTEXT; +} + +function getChildHostContext(parentHostContext, type, rootContainerInstance) { + return NO_CONTEXT; +} + +function prepareForCommit(containerInfo) { + // noop +} + +function resetAfterCommit(containerInfo) { + // noop +} + +function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { + return { + type: type, + props: props, + isHidden: false, + children: [], + rootContainerInstance: rootContainerInstance, + tag: 'INSTANCE' + }; +} + +function appendInitialChild(parentInstance, child) { + var index = parentInstance.children.indexOf(child); + if (index !== -1) { + parentInstance.children.splice(index, 1); + } + parentInstance.children.push(child); +} + +function finalizeInitialChildren(testElement, type, props, rootContainerInstance, hostContext) { + return false; +} + +function prepareUpdate(testElement, type, oldProps, newProps, rootContainerInstance, hostContext) { + return UPDATE_SIGNAL; +} + +function shouldSetTextContent(type, props) { + return false; +} + +function shouldDeprioritizeSubtree(type, props) { + return false; +} + +function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { + return { + text: text, + isHidden: false, + tag: 'TEXT' + }; +} + +var isPrimaryRenderer = false; +// This approach enables `now` to be mocked by tests, +// Even after the reconciler has initialized and read host config values. +var now = function () { + return nowImplementation(); +}; +var scheduleDeferredCallback$$1 = scheduleDeferredCallback$1; +var cancelDeferredCallback$$1 = cancelDeferredCallback$1; +var shouldYield$$1 = shouldYield$1; + +var scheduleTimeout = setTimeout; +var cancelTimeout = clearTimeout; +var noTimeout = -1; +var schedulePassiveEffects = scheduleDeferredCallback$$1; +var cancelPassiveEffects = cancelDeferredCallback$$1; + +// ------------------- +// Mutation +// ------------------- + +var supportsMutation = true; + +function commitUpdate(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle) { + instance.type = type; + instance.props = newProps; +} + + + +function commitTextUpdate(textInstance, oldText, newText) { + textInstance.text = newText; +} + +function resetTextContent(testElement) { + // noop +} + +var appendChildToContainer = appendChild; +var insertInContainerBefore = insertBefore; +var removeChildFromContainer = removeChild; + +function hideInstance(instance) { + instance.isHidden = true; +} + +function hideTextInstance(textInstance) { + textInstance.isHidden = true; +} + +function unhideInstance(instance, props) { + instance.isHidden = false; +} + +function unhideTextInstance(textInstance, text) { + textInstance.isHidden = false; +} + +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +var BEFORE_SLASH_RE = /^(.*)[\\\/]/; + +var describeComponentFrame = function (name, source, ownerName) { + var sourceInfo = ''; + if (source) { + var path = source.fileName; + var fileName = path.replace(BEFORE_SLASH_RE, ''); + sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; + } else if (ownerName) { + sourceInfo = ' (created by ' + ownerName + ')'; + } + return '\n in ' + (name || 'Unknown') + sourceInfo; +}; + +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + +function describeFiber(fiber) { + switch (fiber.tag) { + case HostRoot: + case HostPortal: + case HostText: + case Fragment: + case ContextProvider: + case ContextConsumer: + return ''; + default: + var owner = fiber._debugOwner; + var source = fiber._debugSource; + var name = getComponentName(fiber.type); + var ownerName = null; + if (owner) { + ownerName = getComponentName(owner.type); + } + return describeComponentFrame(name, source, ownerName); + } +} + +function getStackByFiberInDevAndProd(workInProgress) { + var info = ''; + var node = workInProgress; + do { + info += describeFiber(node); + node = node.return; + } while (node); + return info; +} + +var enableUserTimingAPI = false; + + +var enableProfilerTimer = false; +var enableSchedulerTracing = false; +var enableSuspenseServerRenderer = false; + + + + + +// Only used in www builds. + +// Prefix measurements so that it's possible to filter them. +// Longer prefixes are hard to read in DevTools. +var reactEmoji = '\u269B'; +var warningEmoji = '\u26D4'; +var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function'; + +// Keep track of current fiber so that we know the path to unwind on pause. +// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? +var currentFiber = null; +// If we're in the middle of user code, which fiber and method is it? +// Reusing `currentFiber` would be confusing for this because user code fiber +// can change during commit phase too, but we don't need to unwind it (since +// lifecycles in the commit phase don't resemble a tree). +var currentPhase = null; +var currentPhaseFiber = null; +// Did lifecycle hook schedule an update? This is often a performance problem, +// so we will keep track of it, and include it in the report. +// Track commits caused by cascading updates. +var isCommitting = false; +var hasScheduledUpdateInCurrentCommit = false; +var hasScheduledUpdateInCurrentPhase = false; +var commitCountInCurrentWorkLoop = 0; +var effectCountInCurrentCommit = 0; +var isWaitingForCallback = false; +// During commits, we only show a measurement once per method name +// to avoid stretch the commit phase with measurement overhead. +var labelsInCurrentCommit = new Set(); + +var formatMarkName = function (markName) { + return reactEmoji + ' ' + markName; +}; + +var formatLabel = function (label, warning) { + var prefix = warning ? warningEmoji + ' ' : reactEmoji + ' '; + var suffix = warning ? ' Warning: ' + warning : ''; + return '' + prefix + label + suffix; +}; + +var beginMark = function (markName) { + performance.mark(formatMarkName(markName)); +}; + +var clearMark = function (markName) { + performance.clearMarks(formatMarkName(markName)); +}; + +var endMark = function (label, markName, warning) { + var formattedMarkName = formatMarkName(markName); + var formattedLabel = formatLabel(label, warning); + try { + performance.measure(formattedLabel, formattedMarkName); + } catch (err) {} + // If previous mark was missing for some reason, this will throw. + // This could only happen if React crashed in an unexpected place earlier. + // Don't pile on with more errors. + + // Clear marks immediately to avoid growing buffer. + performance.clearMarks(formattedMarkName); + performance.clearMeasures(formattedLabel); +}; + +var getFiberMarkName = function (label, debugID) { + return label + ' (#' + debugID + ')'; +}; + +var getFiberLabel = function (componentName, isMounted, phase) { + if (phase === null) { + // These are composite component total time measurements. + return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']'; + } else { + // Composite component methods. + return componentName + '.' + phase; + } +}; + +var beginFiberMark = function (fiber, phase) { + var componentName = getComponentName(fiber.type) || 'Unknown'; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + + if (isCommitting && labelsInCurrentCommit.has(label)) { + // During the commit phase, we don't show duplicate labels because + // there is a fixed overhead for every measurement, and we don't + // want to stretch the commit phase beyond necessary. + return false; + } + labelsInCurrentCommit.add(label); + + var markName = getFiberMarkName(label, debugID); + beginMark(markName); + return true; +}; + +var clearFiberMark = function (fiber, phase) { + var componentName = getComponentName(fiber.type) || 'Unknown'; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + clearMark(markName); +}; + +var endFiberMark = function (fiber, phase, warning) { + var componentName = getComponentName(fiber.type) || 'Unknown'; + var debugID = fiber._debugID; + var isMounted = fiber.alternate !== null; + var label = getFiberLabel(componentName, isMounted, phase); + var markName = getFiberMarkName(label, debugID); + endMark(label, markName, warning); +}; + +var shouldIgnoreFiber = function (fiber) { + // Host components should be skipped in the timeline. + // We could check typeof fiber.type, but does this work with RN? + switch (fiber.tag) { + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case Fragment: + case ContextProvider: + case ContextConsumer: + case Mode: + return true; + default: + return false; + } +}; + +var clearPendingPhaseMeasurement = function () { + if (currentPhase !== null && currentPhaseFiber !== null) { + clearFiberMark(currentPhaseFiber, currentPhase); + } + currentPhaseFiber = null; + currentPhase = null; + hasScheduledUpdateInCurrentPhase = false; +}; + +var pauseTimers = function () { + // Stops all currently active measurements so that they can be resumed + // if we continue in a later deferred loop from the same unit of work. + var fiber = currentFiber; + while (fiber) { + if (fiber._debugIsCurrentlyTiming) { + endFiberMark(fiber, null, null); + } + fiber = fiber.return; + } +}; + +var resumeTimersRecursively = function (fiber) { + if (fiber.return !== null) { + resumeTimersRecursively(fiber.return); + } + if (fiber._debugIsCurrentlyTiming) { + beginFiberMark(fiber, null); + } +}; + +var resumeTimers = function () { + // Resumes all measurements that were active during the last deferred loop. + if (currentFiber !== null) { + resumeTimersRecursively(currentFiber); + } +}; + +function recordEffect() { + if (enableUserTimingAPI) { + effectCountInCurrentCommit++; + } +} + +function recordScheduleUpdate() { + if (enableUserTimingAPI) { + if (isCommitting) { + hasScheduledUpdateInCurrentCommit = true; + } + if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { + hasScheduledUpdateInCurrentPhase = true; + } + } +} + +function startRequestCallbackTimer() { + if (enableUserTimingAPI) { + if (supportsUserTiming && !isWaitingForCallback) { + isWaitingForCallback = true; + beginMark('(Waiting for async callback...)'); + } + } +} + +function stopRequestCallbackTimer(didExpire, expirationTime) { + if (enableUserTimingAPI) { + if (supportsUserTiming) { + isWaitingForCallback = false; + var warning = didExpire ? 'React was blocked by main thread' : null; + endMark('(Waiting for async callback... will force flush in ' + expirationTime + ' ms)', '(Waiting for async callback...)', warning); + } + } +} + +function startWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, this is the fiber to unwind from. + currentFiber = fiber; + if (!beginFiberMark(fiber, null)) { + return; + } + fiber._debugIsCurrentlyTiming = true; + } +} + +function cancelWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // Remember we shouldn't complete measurement for this fiber. + // Otherwise flamechart will be deep even for small updates. + fiber._debugIsCurrentlyTiming = false; + clearFiberMark(fiber, null); + } +} + +function stopWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + endFiberMark(fiber, null, null); + } +} + +function stopFailedWorkTimer(fiber) { + if (enableUserTimingAPI) { + if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { + return; + } + // If we pause, its parent is the fiber to unwind from. + currentFiber = fiber.return; + if (!fiber._debugIsCurrentlyTiming) { + return; + } + fiber._debugIsCurrentlyTiming = false; + var warning = fiber.tag === SuspenseComponent || fiber.tag === DehydratedSuspenseComponent ? 'Rendering was suspended' : 'An error was thrown inside this error boundary'; + endFiberMark(fiber, null, warning); + } +} + +function startPhaseTimer(fiber, phase) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + clearPendingPhaseMeasurement(); + if (!beginFiberMark(fiber, phase)) { + return; + } + currentPhaseFiber = fiber; + currentPhase = phase; + } +} + +function stopPhaseTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + if (currentPhase !== null && currentPhaseFiber !== null) { + var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; + endFiberMark(currentPhaseFiber, currentPhase, warning); + } + currentPhase = null; + currentPhaseFiber = null; + } +} + +function startWorkLoopTimer(nextUnitOfWork) { + if (enableUserTimingAPI) { + currentFiber = nextUnitOfWork; + if (!supportsUserTiming) { + return; + } + commitCountInCurrentWorkLoop = 0; + // This is top level call. + // Any other measurements are performed within. + beginMark('(React Tree Reconciliation)'); + // Resume any measurements that were in progress during the last loop. + resumeTimers(); + } +} + +function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var warning = null; + if (interruptedBy !== null) { + if (interruptedBy.tag === HostRoot) { + warning = 'A top-level update interrupted the previous render'; + } else { + var componentName = getComponentName(interruptedBy.type) || 'Unknown'; + warning = 'An update to ' + componentName + ' interrupted the previous render'; + } + } else if (commitCountInCurrentWorkLoop > 1) { + warning = 'There were cascading updates'; + } + commitCountInCurrentWorkLoop = 0; + var label = didCompleteRoot ? '(React Tree Reconciliation: Completed Root)' : '(React Tree Reconciliation: Yielded)'; + // Pause any measurements until the next loop. + pauseTimers(); + endMark(label, '(React Tree Reconciliation)', warning); + } +} + +function startCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + isCommitting = true; + hasScheduledUpdateInCurrentCommit = false; + labelsInCurrentCommit.clear(); + beginMark('(Committing Changes)'); + } +} + +function stopCommitTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + + var warning = null; + if (hasScheduledUpdateInCurrentCommit) { + warning = 'Lifecycle hook scheduled a cascading update'; + } else if (commitCountInCurrentWorkLoop > 0) { + warning = 'Caused by a cascading update in earlier commit'; + } + hasScheduledUpdateInCurrentCommit = false; + commitCountInCurrentWorkLoop++; + isCommitting = false; + labelsInCurrentCommit.clear(); + + endMark('(Committing Changes)', '(Committing Changes)', warning); + } +} + +function startCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark('(Committing Snapshot Effects)'); + } +} + +function stopCommitSnapshotEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark('(Committing Snapshot Effects: ' + count + ' Total)', '(Committing Snapshot Effects)', null); + } +} + +function startCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark('(Committing Host Effects)'); + } +} + +function stopCommitHostEffectsTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); + } +} + +function startCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + effectCountInCurrentCommit = 0; + beginMark('(Calling Lifecycle Methods)'); + } +} + +function stopCommitLifeCyclesTimer() { + if (enableUserTimingAPI) { + if (!supportsUserTiming) { + return; + } + var count = effectCountInCurrentCommit; + effectCountInCurrentCommit = 0; + endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); + } +} + +var valueStack = []; + +var index = -1; + +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} + +function pop(cursor, fiber) { + if (index < 0) { + return; + } + + cursor.current = valueStack[index]; + + valueStack[index] = null; + + index--; +} + +function push(cursor, value, fiber) { + index++; + + valueStack[index] = cursor.current; + + cursor.current = value; +} + +var emptyContextObject = {}; +// A cursor to the current merged context object on the stack. +var contextStackCursor = createCursor(emptyContextObject); +// A cursor to a boolean indicating whether the context has changed. +var didPerformWorkStackCursor = createCursor(false); +// Keep track of the previous context object that was on the stack. +// We use this to get access to the parent context after we have already +// pushed the next context provider, and now need to merge their contexts. +var previousContext = emptyContextObject; + +function getUnmaskedContext(workInProgress, Component, didPushOwnContextIfProvider) { + if (didPushOwnContextIfProvider && isContextProvider(Component)) { + // If the fiber is a context provider itself, when we read its context + // we may have already pushed its own child context on the stack. A context + // provider should not "see" its own child context. Therefore we read the + // previous (parent) context instead for a context provider. + return previousContext; + } + return contextStackCursor.current; +} + +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; +} + +function getMaskedContext(workInProgress, unmaskedContext) { + var type = workInProgress.type; + var contextTypes = type.contextTypes; + if (!contextTypes) { + return emptyContextObject; + } + + // Avoid recreating masked context unless unmasked context has changed. + // Failing to do this will result in unnecessary calls to componentWillReceiveProps. + // This may trigger infinite loops if componentWillReceiveProps calls setState. + var instance = workInProgress.stateNode; + if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { + return instance.__reactInternalMemoizedMaskedChildContext; + } + + var context = {}; + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } + + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return context; +} + +function hasContextChanged() { + return didPerformWorkStackCursor.current; +} + +function isContextProvider(type) { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; +} + +function popContext(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function popTopLevelContextObject(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); +} + +function pushTopLevelContextObject(fiber, context, didChange) { + !(contextStackCursor.current === emptyContextObject) ? reactProdInvariant('168') : void 0; + + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); +} + +function processChildContext(fiber, type, parentContext) { + var instance = fiber.stateNode; + var childContextTypes = type.childContextTypes; + + // TODO (bvaughn) Replace this behavior with an invariant() in the future. + // It has only been added in Fiber to match the (unintentional) behavior in Stack. + if (typeof instance.getChildContext !== 'function') { + return parentContext; + } + + var childContext = void 0; + startPhaseTimer(fiber, 'getChildContext'); + childContext = instance.getChildContext(); + stopPhaseTimer(); + for (var contextKey in childContext) { + !(contextKey in childContextTypes) ? reactProdInvariant('108', getComponentName(type) || 'Unknown', contextKey) : void 0; + } + return _assign({}, parentContext, childContext); +} + +function pushContextProvider(workInProgress) { + var instance = workInProgress.stateNode; + // We push the context as early as possible to ensure stack integrity. + // If the instance does not exist yet, we will push null at first, + // and replace it on the stack later when invalidating the context. + var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyContextObject; + + // Remember the parent context so we can merge with it later. + // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. + previousContext = contextStackCursor.current; + push(contextStackCursor, memoizedMergedChildContext, workInProgress); + push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); + + return true; +} + +function invalidateContextProvider(workInProgress, type, didChange) { + var instance = workInProgress.stateNode; + !instance ? reactProdInvariant('169') : void 0; + + if (didChange) { + // Merge parent and own context. + // Skip this if we're not updating due to sCU. + // This avoids unnecessarily recomputing memoized values. + var mergedContext = processChildContext(workInProgress, type, previousContext); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + + // Replace the old (or empty) context with the new one. + // It is important to unwind the context in the reverse order. + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + // Now push the new context and mark that it has changed. + push(contextStackCursor, mergedContext, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } else { + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + } +} + +function findCurrentUnmaskedContext(fiber) { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + !(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? reactProdInvariant('170') : void 0; + + var node = fiber; + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; + case ClassComponent: + { + var Component = node.type; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + break; + } + } + node = node.return; + } while (node !== null); + reactProdInvariant('171'); +} + +var onCommitFiberRoot = null; +var onCommitFiberUnmount = null; +function catchErrors(fn) { + return function (arg) { + try { + return fn(arg); + } catch (err) { + + } + }; +} + +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined'; + +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { + // No DevTools + return false; + } + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; + } + if (!hook.supportsFiber) { + return true; + } + try { + var rendererID = hook.inject(internals); + // We have successfully injected, so now it is safe to set up hooks. + onCommitFiberRoot = catchErrors(function (root) { + return hook.onCommitFiberRoot(rendererID, root); + }); + onCommitFiberUnmount = catchErrors(function (fiber) { + return hook.onCommitFiberUnmount(rendererID, fiber); + }); + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + + } + // DevTools exists + return true; +} + +function onCommitRoot(root) { + if (typeof onCommitFiberRoot === 'function') { + onCommitFiberRoot(root); + } +} + +function onCommitUnmount(fiber) { + if (typeof onCommitFiberUnmount === 'function') { + onCommitFiberUnmount(fiber); + } +} + +// Max 31 bit integer. The max integer size in V8 for 32-bit systems. +// Math.pow(2, 30) - 1 +// 0b111111111111111111111111111111 +var maxSigned31BitInt = 1073741823; + +var NoWork = 0; +var Never = 1; +var Sync = maxSigned31BitInt; + +var UNIT_SIZE = 10; +var MAGIC_NUMBER_OFFSET = maxSigned31BitInt - 1; + +// 1 unit of expiration time represents 10ms. +function msToExpirationTime(ms) { + // Always add an offset so that we don't clash with the magic number for NoWork. + return MAGIC_NUMBER_OFFSET - (ms / UNIT_SIZE | 0); +} + +function expirationTimeToMs(expirationTime) { + return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; +} + +function ceiling(num, precision) { + return ((num / precision | 0) + 1) * precision; +} + +function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { + return MAGIC_NUMBER_OFFSET - ceiling(MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE); +} + +var LOW_PRIORITY_EXPIRATION = 5000; +var LOW_PRIORITY_BATCH_SIZE = 250; + +function computeAsyncExpiration(currentTime) { + return computeExpirationBucket(currentTime, LOW_PRIORITY_EXPIRATION, LOW_PRIORITY_BATCH_SIZE); +} + +// We intentionally set a higher expiration time for interactive updates in +// dev than in production. +// +// If the main thread is being blocked so long that you hit the expiration, +// it's a problem that could be solved with better scheduling. +// +// People will be more likely to notice this and fix it with the long +// expiration time in development. +// +// In production we opt for better UX at the risk of masking scheduling +// problems, by expiring fast. +var HIGH_PRIORITY_EXPIRATION = 150; +var HIGH_PRIORITY_BATCH_SIZE = 100; + +function computeInteractiveExpiration(currentTime) { + return computeExpirationBucket(currentTime, HIGH_PRIORITY_EXPIRATION, HIGH_PRIORITY_BATCH_SIZE); +} + +var NoContext = 0; +var ConcurrentMode = 1; +var StrictMode = 2; +var ProfileMode = 4; + +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; + + // Fiber + this.return = null; + this.child = null; + this.sibling = null; + this.index = 0; + + this.ref = null; + + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; + this.contextDependencies = null; + + this.mode = mode; + + // Effects + this.effectTag = NoEffect; + this.nextEffect = null; + + this.firstEffect = null; + this.lastEffect = null; + + this.expirationTime = NoWork; + this.childExpirationTime = NoWork; + + this.alternate = null; + + if (enableProfilerTimer) { + // Note: The following is done to avoid a v8 performance cliff. + // + // Initializing the fields below to smis and later updating them with + // double values will cause Fibers to end up having separate shapes. + // This behavior/bug has something to do with Object.preventExtension(). + // Fortunately this only impacts DEV builds. + // Unfortunately it makes React unusably slow for some applications. + // To work around this, initialize the fields below with doubles. + // + // Learn more about this here: + // https://github.com/facebook/react/issues/14365 + // https://bugs.chromium.org/p/v8/issues/detail?id=8538 + this.actualDuration = Number.NaN; + this.actualStartTime = Number.NaN; + this.selfBaseDuration = Number.NaN; + this.treeBaseDuration = Number.NaN; + + // It's okay to replace the initial doubles with smis after initialization. + // This won't trigger the performance cliff mentioned above, + // and it simplifies other profiler code (including DevTools). + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } + + +} + +// This is a constructor function, rather than a POJO constructor, still +// please ensure we do the following: +// 1) Nobody should add any instance methods on this. Instance methods can be +// more difficult to predict when they get optimized and they are almost +// never inlined properly in static compilers. +// 2) Nobody should rely on `instanceof Fiber` for type testing. We should +// always know when it is a fiber. +// 3) We might want to experiment with using numeric keys since they are easier +// to optimize in a non-JIT environment. +// 4) We can easily go from a constructor to a createFiber object literal if that +// is faster. +// 5) It should be easy to port this to a C struct and keep a C implementation +// compatible. +var createFiber = function (tag, pendingProps, key, mode) { + // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +}; + +function shouldConstruct(Component) { + var prototype = Component.prototype; + return !!(prototype && prototype.isReactComponent); +} + +function isSimpleFunctionComponent(type) { + return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined; +} + +function resolveLazyComponentTag(Component) { + if (typeof Component === 'function') { + return shouldConstruct(Component) ? ClassComponent : FunctionComponent; + } else if (Component !== undefined && Component !== null) { + var $$typeof = Component.$$typeof; + if ($$typeof === REACT_FORWARD_REF_TYPE) { + return ForwardRef; + } + if ($$typeof === REACT_MEMO_TYPE) { + return MemoComponent; + } + } + return IndeterminateComponent; +} + +// This is used to create an alternate fiber to do work on. +function createWorkInProgress(current, pendingProps, expirationTime) { + var workInProgress = current.alternate; + if (workInProgress === null) { + // We use a double buffering pooling technique because we know that we'll + // only ever need at most two versions of a tree. We pool the "other" unused + // node that we're free to reuse. This is lazily created to avoid allocating + // extra objects for things that are never updated. It also allow us to + // reclaim the extra memory if needed. + workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode); + workInProgress.elementType = current.elementType; + workInProgress.type = current.type; + workInProgress.stateNode = current.stateNode; + + workInProgress.alternate = current; + current.alternate = workInProgress; + } else { + workInProgress.pendingProps = pendingProps; + + // We already have an alternate. + // Reset the effect tag. + workInProgress.effectTag = NoEffect; + + // The effect list is no longer valid. + workInProgress.nextEffect = null; + workInProgress.firstEffect = null; + workInProgress.lastEffect = null; + + if (enableProfilerTimer) { + // We intentionally reset, rather than copy, actualDuration & actualStartTime. + // This prevents time from endlessly accumulating in new commits. + // This has the downside of resetting values for different priority renders, + // But works for yielding (the common case) and should support resuming. + workInProgress.actualDuration = 0; + workInProgress.actualStartTime = -1; + } + } + + workInProgress.childExpirationTime = current.childExpirationTime; + workInProgress.expirationTime = current.expirationTime; + + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; + workInProgress.contextDependencies = current.contextDependencies; + + // These will be overridden during the parent's reconciliation + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + + if (enableProfilerTimer) { + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } + + return workInProgress; +} + +function createHostRootFiber(isConcurrent) { + var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; + + if (enableProfilerTimer && isDevToolsPresent) { + // Always collect profile timings when DevTools are present. + // This enables DevTools to start capturing timing at any point– + // Without some nodes in the tree having empty base times. + mode |= ProfileMode; + } + + return createFiber(HostRoot, null, null, mode); +} + +function createFiberFromTypeAndProps(type, // React$ElementType +key, pendingProps, owner, mode, expirationTime) { + var fiber = void 0; + + var fiberTag = IndeterminateComponent; + // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + var resolvedType = type; + if (typeof type === 'function') { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; + } + } else if (typeof type === 'string') { + fiberTag = HostComponent; + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment(pendingProps.children, mode, expirationTime, key); + case REACT_CONCURRENT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | ConcurrentMode | StrictMode, expirationTime, key); + case REACT_STRICT_MODE_TYPE: + return createFiberFromMode(pendingProps, mode | StrictMode, expirationTime, key); + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, expirationTime, key); + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, expirationTime, key); + default: + { + if (typeof type === 'object' && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break getTag; + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break getTag; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; + break getTag; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; + } + } + var info = ''; + reactProdInvariant('130', type == null ? type : typeof type, info); + } + } + } + + fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromElement(element, mode, expirationTime) { + var owner = null; + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime); + return fiber; +} + +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + // TODO: The Profiler fiber shouldn't have a type. It has a tag. + fiber.elementType = REACT_PROFILER_TYPE; + fiber.type = REACT_PROFILER_TYPE; + fiber.expirationTime = expirationTime; + + return fiber; +} + +function createFiberFromMode(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(Mode, pendingProps, key, mode); + + // TODO: The Mode fiber shouldn't have a type. It has a tag. + var type = (mode & ConcurrentMode) === NoContext ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { + var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + + // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. + var type = REACT_SUSPENSE_TYPE; + fiber.elementType = type; + fiber.type = type; + + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); + fiber.expirationTime = expirationTime; + return fiber; +} + +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoContext); + // TODO: These should not need a type. + fiber.elementType = 'DELETED'; + fiber.type = 'DELETED'; + return fiber; +} + +function createFiberFromPortal(portal, mode, expirationTime) { + var pendingProps = portal.children !== null ? portal.children : []; + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); + fiber.expirationTime = expirationTime; + fiber.stateNode = { + containerInfo: portal.containerInfo, + pendingChildren: null, // Used by persistent updates + implementation: portal.implementation + }; + return fiber; +} + +// Used for stashing WIP properties to replay failed work in DEV. + +var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var _ReactInternals$Sched = ReactInternals$1.SchedulerTracing; +var __interactionsRef = _ReactInternals$Sched.__interactionsRef; +var __subscriberRef = _ReactInternals$Sched.__subscriberRef; +var unstable_clear = _ReactInternals$Sched.unstable_clear; +var unstable_getCurrent = _ReactInternals$Sched.unstable_getCurrent; +var unstable_getThreadID = _ReactInternals$Sched.unstable_getThreadID; +var unstable_subscribe = _ReactInternals$Sched.unstable_subscribe; +var unstable_trace = _ReactInternals$Sched.unstable_trace; +var unstable_unsubscribe = _ReactInternals$Sched.unstable_unsubscribe; +var unstable_wrap = _ReactInternals$Sched.unstable_wrap; + +// TODO: This should be lifted into the renderer. + + +// The following attributes are only used by interaction tracing builds. +// They enable interactions to be associated with their async work, +// And expose interaction metadata to the React DevTools Profiler plugin. +// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. + + +// Exported FiberRoot type includes all properties, +// To avoid requiring potentially error-prone :any casts throughout the project. +// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). +// The types are defined separately within this file to ensure they stay in sync. +// (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) + + +function createFiberRoot(containerInfo, isConcurrent, hydrate) { + // Cyclic construction. This cheats the type system right now because + // stateNode is any. + var uninitializedFiber = createHostRootFiber(isConcurrent); + + var root = void 0; + if (enableSchedulerTracing) { + root = { + current: uninitializedFiber, + containerInfo: containerInfo, + pendingChildren: null, + + earliestPendingTime: NoWork, + latestPendingTime: NoWork, + earliestSuspendedTime: NoWork, + latestSuspendedTime: NoWork, + latestPingedTime: NoWork, + + pingCache: null, + + didError: false, + + pendingCommitExpirationTime: NoWork, + finishedWork: null, + timeoutHandle: noTimeout, + context: null, + pendingContext: null, + hydrate: hydrate, + nextExpirationTimeToWorkOn: NoWork, + expirationTime: NoWork, + firstBatch: null, + nextScheduledRoot: null, + + interactionThreadID: unstable_getThreadID(), + memoizedInteractions: new Set(), + pendingInteractionMap: new Map() + }; + } else { + root = { + current: uninitializedFiber, + containerInfo: containerInfo, + pendingChildren: null, + + pingCache: null, + + earliestPendingTime: NoWork, + latestPendingTime: NoWork, + earliestSuspendedTime: NoWork, + latestSuspendedTime: NoWork, + latestPingedTime: NoWork, + + didError: false, + + pendingCommitExpirationTime: NoWork, + finishedWork: null, + timeoutHandle: noTimeout, + context: null, + pendingContext: null, + hydrate: hydrate, + nextExpirationTimeToWorkOn: NoWork, + expirationTime: NoWork, + firstBatch: null, + nextScheduledRoot: null + }; + } + + uninitializedFiber.stateNode = root; + + // The reason for the way the Flow types are structured in this file, + // Is to avoid needing :any casts everywhere interaction tracing fields are used. + // Unfortunately that requires an :any cast for non-interaction tracing capable builds. + // $FlowFixMe Remove this :any cast and replace it with something better. + return root; +} + +var ReactInternals$2 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var _ReactInternals$Sched$1 = ReactInternals$2.Scheduler; +var unstable_cancelCallback = _ReactInternals$Sched$1.unstable_cancelCallback; +var unstable_now = _ReactInternals$Sched$1.unstable_now; +var unstable_scheduleCallback = _ReactInternals$Sched$1.unstable_scheduleCallback; +var unstable_shouldYield = _ReactInternals$Sched$1.unstable_shouldYield; +var unstable_getFirstCallbackNode = _ReactInternals$Sched$1.unstable_getFirstCallbackNode; +var unstable_runWithPriority = _ReactInternals$Sched$1.unstable_runWithPriority; +var unstable_next = _ReactInternals$Sched$1.unstable_next; +var unstable_continueExecution = _ReactInternals$Sched$1.unstable_continueExecution; +var unstable_pauseExecution = _ReactInternals$Sched$1.unstable_pauseExecution; +var unstable_getCurrentPriorityLevel = _ReactInternals$Sched$1.unstable_getCurrentPriorityLevel; +var unstable_ImmediatePriority = _ReactInternals$Sched$1.unstable_ImmediatePriority; +var unstable_UserBlockingPriority = _ReactInternals$Sched$1.unstable_UserBlockingPriority; +var unstable_NormalPriority = _ReactInternals$Sched$1.unstable_NormalPriority; +var unstable_LowPriority = _ReactInternals$Sched$1.unstable_LowPriority; +var unstable_IdlePriority = _ReactInternals$Sched$1.unstable_IdlePriority; + +/** + * Call a function while guarding against errors that happens within it. + * Returns an error if it throws, otherwise null. + * + * In production, this is implemented using a try-catch. The reason we don't + * use a try-catch directly is so that we can swap out a different + * implementation in DEV mode. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ + + +/** + * Same as invokeGuardedCallback, but instead of returning an error, it stores + * it in a global so it can be rethrown by `rethrowCaughtError` later. + * TODO: See if caughtError and rethrowError can be unified. + * + * @param {String} name of the guard to use for logging or debugging + * @param {Function} func The function to invoke + * @param {*} context The context to use when calling the function + * @param {...*} args Arguments for function + */ + + +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ + +/** + * Forked from fbjs/warning: + * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js + * + * Only change is we use console.warn instead of console.error, + * and do nothing when 'console' is not supported. + * This really simplifies the code. + * --- + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + +// This lets us hook into Fiber to debug what it's doing. +// See https://github.com/facebook/react/pull/8033. +// This is not part of the public API, not even for React DevTools. +// You may only inject a debugTool if you work on React Fiber itself. + +// TODO: Offscreen updates should never suspend. However, a promise that +// suspended inside an offscreen subtree should be able to ping at the priority +// of the outer render. + +function markPendingPriorityLevel(root, expirationTime) { + // If there's a gap between completing a failed root and retrying it, + // additional updates may be scheduled. Clear `didError`, in case the update + // is sufficient to fix the error. + root.didError = false; + + // Update the latest and earliest pending times + var earliestPendingTime = root.earliestPendingTime; + if (earliestPendingTime === NoWork) { + // No other pending updates. + root.earliestPendingTime = root.latestPendingTime = expirationTime; + } else { + if (earliestPendingTime < expirationTime) { + // This is the earliest pending update. + root.earliestPendingTime = expirationTime; + } else { + var latestPendingTime = root.latestPendingTime; + if (latestPendingTime > expirationTime) { + // This is the latest pending update + root.latestPendingTime = expirationTime; + } + } + } + findNextExpirationTimeToWorkOn(expirationTime, root); +} + +function markCommittedPriorityLevels(root, earliestRemainingTime) { + root.didError = false; + + if (earliestRemainingTime === NoWork) { + // Fast path. There's no remaining work. Clear everything. + root.earliestPendingTime = NoWork; + root.latestPendingTime = NoWork; + root.earliestSuspendedTime = NoWork; + root.latestSuspendedTime = NoWork; + root.latestPingedTime = NoWork; + findNextExpirationTimeToWorkOn(NoWork, root); + return; + } + + if (earliestRemainingTime < root.latestPingedTime) { + root.latestPingedTime = NoWork; + } + + // Let's see if the previous latest known pending level was just flushed. + var latestPendingTime = root.latestPendingTime; + if (latestPendingTime !== NoWork) { + if (latestPendingTime > earliestRemainingTime) { + // We've flushed all the known pending levels. + root.earliestPendingTime = root.latestPendingTime = NoWork; + } else { + var earliestPendingTime = root.earliestPendingTime; + if (earliestPendingTime > earliestRemainingTime) { + // We've flushed the earliest known pending level. Set this to the + // latest pending time. + root.earliestPendingTime = root.latestPendingTime; + } + } + } + + // Now let's handle the earliest remaining level in the whole tree. We need to + // decide whether to treat it as a pending level or as suspended. Check + // it falls within the range of known suspended levels. + + var earliestSuspendedTime = root.earliestSuspendedTime; + if (earliestSuspendedTime === NoWork) { + // There's no suspended work. Treat the earliest remaining level as a + // pending level. + markPendingPriorityLevel(root, earliestRemainingTime); + findNextExpirationTimeToWorkOn(NoWork, root); + return; + } + + var latestSuspendedTime = root.latestSuspendedTime; + if (earliestRemainingTime < latestSuspendedTime) { + // The earliest remaining level is later than all the suspended work. That + // means we've flushed all the suspended work. + root.earliestSuspendedTime = NoWork; + root.latestSuspendedTime = NoWork; + root.latestPingedTime = NoWork; + + // There's no suspended work. Treat the earliest remaining level as a + // pending level. + markPendingPriorityLevel(root, earliestRemainingTime); + findNextExpirationTimeToWorkOn(NoWork, root); + return; + } + + if (earliestRemainingTime > earliestSuspendedTime) { + // The earliest remaining time is earlier than all the suspended work. + // Treat it as a pending update. + markPendingPriorityLevel(root, earliestRemainingTime); + findNextExpirationTimeToWorkOn(NoWork, root); + return; + } + + // The earliest remaining time falls within the range of known suspended + // levels. We should treat this as suspended work. + findNextExpirationTimeToWorkOn(NoWork, root); +} + +function hasLowerPriorityWork(root, erroredExpirationTime) { + var latestPendingTime = root.latestPendingTime; + var latestSuspendedTime = root.latestSuspendedTime; + var latestPingedTime = root.latestPingedTime; + return latestPendingTime !== NoWork && latestPendingTime < erroredExpirationTime || latestSuspendedTime !== NoWork && latestSuspendedTime < erroredExpirationTime || latestPingedTime !== NoWork && latestPingedTime < erroredExpirationTime; +} + +function isPriorityLevelSuspended(root, expirationTime) { + var earliestSuspendedTime = root.earliestSuspendedTime; + var latestSuspendedTime = root.latestSuspendedTime; + return earliestSuspendedTime !== NoWork && expirationTime <= earliestSuspendedTime && expirationTime >= latestSuspendedTime; +} + +function markSuspendedPriorityLevel(root, suspendedTime) { + root.didError = false; + clearPing(root, suspendedTime); + + // First, check the known pending levels and update them if needed. + var earliestPendingTime = root.earliestPendingTime; + var latestPendingTime = root.latestPendingTime; + if (earliestPendingTime === suspendedTime) { + if (latestPendingTime === suspendedTime) { + // Both known pending levels were suspended. Clear them. + root.earliestPendingTime = root.latestPendingTime = NoWork; + } else { + // The earliest pending level was suspended. Clear by setting it to the + // latest pending level. + root.earliestPendingTime = latestPendingTime; + } + } else if (latestPendingTime === suspendedTime) { + // The latest pending level was suspended. Clear by setting it to the + // latest pending level. + root.latestPendingTime = earliestPendingTime; + } + + // Finally, update the known suspended levels. + var earliestSuspendedTime = root.earliestSuspendedTime; + var latestSuspendedTime = root.latestSuspendedTime; + if (earliestSuspendedTime === NoWork) { + // No other suspended levels. + root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime; + } else { + if (earliestSuspendedTime < suspendedTime) { + // This is the earliest suspended level. + root.earliestSuspendedTime = suspendedTime; + } else if (latestSuspendedTime > suspendedTime) { + // This is the latest suspended level + root.latestSuspendedTime = suspendedTime; + } + } + + findNextExpirationTimeToWorkOn(suspendedTime, root); +} + +function markPingedPriorityLevel(root, pingedTime) { + root.didError = false; + + // TODO: When we add back resuming, we need to ensure the progressed work + // is thrown out and not reused during the restarted render. One way to + // invalidate the progressed work is to restart at expirationTime + 1. + var latestPingedTime = root.latestPingedTime; + if (latestPingedTime === NoWork || latestPingedTime > pingedTime) { + root.latestPingedTime = pingedTime; + } + findNextExpirationTimeToWorkOn(pingedTime, root); +} + +function clearPing(root, completedTime) { + var latestPingedTime = root.latestPingedTime; + if (latestPingedTime >= completedTime) { + root.latestPingedTime = NoWork; + } +} + +function findEarliestOutstandingPriorityLevel(root, renderExpirationTime) { + var earliestExpirationTime = renderExpirationTime; + + var earliestPendingTime = root.earliestPendingTime; + var earliestSuspendedTime = root.earliestSuspendedTime; + if (earliestPendingTime > earliestExpirationTime) { + earliestExpirationTime = earliestPendingTime; + } + if (earliestSuspendedTime > earliestExpirationTime) { + earliestExpirationTime = earliestSuspendedTime; + } + return earliestExpirationTime; +} + +function didExpireAtExpirationTime(root, currentTime) { + var expirationTime = root.expirationTime; + if (expirationTime !== NoWork && currentTime <= expirationTime) { + // The root has expired. Flush all work up to the current time. + root.nextExpirationTimeToWorkOn = currentTime; + } +} + +function findNextExpirationTimeToWorkOn(completedExpirationTime, root) { + var earliestSuspendedTime = root.earliestSuspendedTime; + var latestSuspendedTime = root.latestSuspendedTime; + var earliestPendingTime = root.earliestPendingTime; + var latestPingedTime = root.latestPingedTime; + + // Work on the earliest pending time. Failing that, work on the latest + // pinged time. + var nextExpirationTimeToWorkOn = earliestPendingTime !== NoWork ? earliestPendingTime : latestPingedTime; + + // If there is no pending or pinged work, check if there's suspended work + // that's lower priority than what we just completed. + if (nextExpirationTimeToWorkOn === NoWork && (completedExpirationTime === NoWork || latestSuspendedTime < completedExpirationTime)) { + // The lowest priority suspended work is the work most likely to be + // committed next. Let's start rendering it again, so that if it times out, + // it's ready to commit. + nextExpirationTimeToWorkOn = latestSuspendedTime; + } + + var expirationTime = nextExpirationTimeToWorkOn; + if (expirationTime !== NoWork && earliestSuspendedTime > expirationTime) { + // Expire using the earliest known expiration time. + expirationTime = earliestSuspendedTime; + } + + root.nextExpirationTimeToWorkOn = nextExpirationTimeToWorkOn; + root.expirationTime = expirationTime; +} + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x, y) { + return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare + ; +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA, objB) { + if (is(objA, objB)) { + return true; + } + + if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { + return false; + } + + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + for (var i = 0; i < keysA.length; i++) { + if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { + return false; + } + } + + return true; +} + +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = _assign({}, baseProps); + var defaultProps = Component.defaultProps; + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; + } + } + return props; + } + return baseProps; +} + +function readLazyComponentType(lazyComponent) { + var status = lazyComponent._status; + var result = lazyComponent._result; + switch (status) { + case Resolved: + { + var Component = result; + return Component; + } + case Rejected: + { + var error = result; + throw error; + } + case Pending: + { + var thenable = result; + throw thenable; + } + default: + { + lazyComponent._status = Pending; + var ctor = lazyComponent._ctor; + var _thenable = ctor(); + _thenable.then(function (moduleObject) { + if (lazyComponent._status === Pending) { + var defaultExport = moduleObject.default; + lazyComponent._status = Resolved; + lazyComponent._result = defaultExport; + } + }, function (error) { + if (lazyComponent._status === Pending) { + lazyComponent._status = Rejected; + lazyComponent._result = error; + } + }); + // Handle synchronous thenables. + switch (lazyComponent._status) { + case Resolved: + return lazyComponent._result; + case Rejected: + throw lazyComponent._result; + } + lazyComponent._result = _thenable; + throw _thenable; + } + } +} + +// React.Component uses a shared frozen object by default. +// We'll use it to determine whether we need to initialize legacy refs. +var emptyRefsObject = new React.Component().refs; + +function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { + var prevState = workInProgress.memoizedState; + + var partialState = getDerivedStateFromProps(nextProps, prevState); + + var memoizedState = partialState === null || partialState === undefined ? prevState : _assign({}, prevState, partialState); + workInProgress.memoizedState = memoizedState; + + // Once the update queue is empty, persist the derived state onto the + // base state. + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null && workInProgress.expirationTime === NoWork) { + updateQueue.baseState = memoizedState; + } +} + +var classComponentUpdater = { + isMounted: isMounted, + enqueueSetState: function (inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.payload = payload; + if (callback !== undefined && callback !== null) { + update.callback = callback; + } + + flushPassiveEffects$1(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueReplaceState: function (inst, payload, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ReplaceState; + update.payload = payload; + + if (callback !== undefined && callback !== null) { + update.callback = callback; + } + + flushPassiveEffects$1(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + }, + enqueueForceUpdate: function (inst, callback) { + var fiber = get(inst); + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, fiber); + + var update = createUpdate(expirationTime); + update.tag = ForceUpdate; + + if (callback !== undefined && callback !== null) { + update.callback = callback; + } + + flushPassiveEffects$1(); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + } +}; + +function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) { + var instance = workInProgress.stateNode; + if (typeof instance.shouldComponentUpdate === 'function') { + startPhaseTimer(workInProgress, 'shouldComponentUpdate'); + var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); + stopPhaseTimer(); + + return shouldUpdate; + } + + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); + } + + return true; +} + +function adoptClassInstance(workInProgress, instance) { + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; + // The instance needs access to the fiber so that it can schedule updates + set(instance, workInProgress); + +} + +function constructClassInstance(workInProgress, ctor, props, renderExpirationTime) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = null; + var contextType = ctor.contextType; + + if (typeof contextType === 'object' && contextType !== null) { + context = readContext(contextType); + } else { + unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + var contextTypes = ctor.contextTypes; + isLegacyContextConsumer = contextTypes !== null && contextTypes !== undefined; + context = isLegacyContextConsumer ? getMaskedContext(workInProgress, unmaskedContext) : emptyContextObject; + } + + // Instantiate twice to help detect side-effects. + var instance = new ctor(props, context); + var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; + adoptClassInstance(workInProgress, instance); + + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); + } + + return instance; +} + +function callComponentWillMount(workInProgress, instance) { + startPhaseTimer(workInProgress, 'componentWillMount'); + var oldState = instance.state; + + if (typeof instance.componentWillMount === 'function') { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); + } + + stopPhaseTimer(); + + if (oldState !== instance.state) { + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { + var oldState = instance.state; + startPhaseTimer(workInProgress, 'componentWillReceiveProps'); + if (typeof instance.componentWillReceiveProps === 'function') { + instance.componentWillReceiveProps(newProps, nextContext); + } + if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } + stopPhaseTimer(); + + if (instance.state !== oldState) { + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} + +// Invokes the mount life-cycles on a previously never rendered instance. +function mountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = emptyRefsObject; + + var contextType = ctor.contextType; + if (typeof contextType === 'object' && contextType !== null) { + instance.context = readContext(contextType); + } else { + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); + } + + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); + instance.state = workInProgress.memoizedState; + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + instance.state = workInProgress.memoizedState; + } + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { + callComponentWillMount(workInProgress, instance); + // If we had additional state updates during this life-cycle, let's + // process them now. + updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); + instance.state = workInProgress.memoizedState; + } + } + + if (typeof instance.componentDidMount === 'function') { + workInProgress.effectTag |= Update; + } +} + +function resumeMountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === 'object' && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); + newState = workInProgress.memoizedState; + } + if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === 'function') { + workInProgress.effectTag |= Update; + } + return false; + } + + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { + startPhaseTimer(workInProgress, 'componentWillMount'); + if (typeof instance.componentWillMount === 'function') { + instance.componentWillMount(); + } + if (typeof instance.UNSAFE_componentWillMount === 'function') { + instance.UNSAFE_componentWillMount(); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidMount === 'function') { + workInProgress.effectTag |= Update; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidMount === 'function') { + workInProgress.effectTag |= Update; + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +// Invokes the update life-cycles and returns false if it shouldn't rerender. +function updateClassInstance(current, workInProgress, ctor, newProps, renderExpirationTime) { + var instance = workInProgress.stateNode; + + var oldProps = workInProgress.memoizedProps; + instance.props = workInProgress.type === workInProgress.elementType ? oldProps : resolveDefaultProps(workInProgress.type, oldProps); + + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = void 0; + if (typeof contextType === 'object' && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + } + + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; + var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; + + // Note: During these life-cycles, instance.props/instance.state are what + // ever the previously attempted to render - not the "current". However, + // during componentDidUpdate we pass the "current" props. + + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); + } + } + + resetHasForceUpdateBeforeProcessing(); + + var oldState = workInProgress.memoizedState; + var newState = instance.state = oldState; + var updateQueue = workInProgress.updateQueue; + if (updateQueue !== null) { + processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); + newState = workInProgress.memoizedState; + } + + if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === 'function') { + if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === 'function') { + if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { + workInProgress.effectTag |= Snapshot; + } + } + return false; + } + + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); + newState = workInProgress.memoizedState; + } + + var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); + + if (shouldUpdate) { + // In order to support react-lifecycles-compat polyfilled components, + // Unsafe lifecycles should not be invoked for components using the new APIs. + if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function')) { + startPhaseTimer(workInProgress, 'componentWillUpdate'); + if (typeof instance.componentWillUpdate === 'function') { + instance.componentWillUpdate(newProps, newState, nextContext); + } + if (typeof instance.UNSAFE_componentWillUpdate === 'function') { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } + stopPhaseTimer(); + } + if (typeof instance.componentDidUpdate === 'function') { + workInProgress.effectTag |= Update; + } + if (typeof instance.getSnapshotBeforeUpdate === 'function') { + workInProgress.effectTag |= Snapshot; + } + } else { + // If an update was already in progress, we should schedule an Update + // effect even though we're bailing out, so that cWU/cDU are called. + if (typeof instance.componentDidUpdate === 'function') { + if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { + workInProgress.effectTag |= Update; + } + } + if (typeof instance.getSnapshotBeforeUpdate === 'function') { + if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { + workInProgress.effectTag |= Snapshot; + } + } + + // If shouldComponentUpdate returned false, we should still update the + // memoized props/state to indicate that this work can be reused. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } + + // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + + return shouldUpdate; +} + +var isArray = Array.isArray; + +function coerceRef(returnFiber, current$$1, element) { + var mixedRef = element.ref; + if (mixedRef !== null && typeof mixedRef !== 'function' && typeof mixedRef !== 'object') { + if (element._owner) { + var owner = element._owner; + var inst = void 0; + if (owner) { + var ownerFiber = owner; + !(ownerFiber.tag === ClassComponent) ? reactProdInvariant('309') : void 0; + inst = ownerFiber.stateNode; + } + !inst ? reactProdInvariant('147', mixedRef) : void 0; + var stringRef = '' + mixedRef; + // Check if previous string ref matches new string ref + if (current$$1 !== null && current$$1.ref !== null && typeof current$$1.ref === 'function' && current$$1.ref._stringRef === stringRef) { + return current$$1.ref; + } + var ref = function (value) { + var refs = inst.refs; + if (refs === emptyRefsObject) { + // This is a lazy pooled frozen object, so we need to initialize. + refs = inst.refs = {}; + } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; + } + }; + ref._stringRef = stringRef; + return ref; + } else { + !(typeof mixedRef === 'string') ? reactProdInvariant('284') : void 0; + !element._owner ? reactProdInvariant('290', mixedRef) : void 0; + } + } + return mixedRef; +} + +function throwOnInvalidObjectType(returnFiber, newChild) { + if (returnFiber.type !== 'textarea') { + var addendum = ''; + reactProdInvariant('31', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum); + } +} + +// This wrapper function exists because I expect to clone the code in each path +// to be able to optimize each path individually by branching early. This needs +// a compiler or we can do it manually. Helpers that don't need this branching +// live outside of this function. +function ChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } + // Deletions are added in reversed order so we add it to the front. + // At this point, the return fiber's effect list is empty except for + // deletions, so we can just append the deletion to the list. The remaining + // effects aren't added until the complete phase. Once we implement + // resuming, this may not be true. + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } + childToDelete.nextEffect = null; + childToDelete.effectTag = Deletion; + } + + function deleteRemainingChildren(returnFiber, currentFirstChild) { + if (!shouldTrackSideEffects) { + // Noop. + return null; + } + + // TODO: For the shouldClone case, this could be micro-optimized a bit by + // assuming that after the first child we've already added everything. + var childToDelete = currentFirstChild; + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } + return null; + } + + function mapRemainingChildren(returnFiber, currentFirstChild) { + // Add the remaining children to a temporary map so that we can find them by + // keys quickly. Implicit (null) keys get added to this set with their index + var existingChildren = new Map(); + + var existingChild = currentFirstChild; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } + existingChild = existingChild.sibling; + } + return existingChildren; + } + + function useFiber(fiber, pendingProps, expirationTime) { + // We currently set sibling to null and index to 0 here because it is easy + // to forget to do before returning it. E.g. for the single child case. + var clone = createWorkInProgress(fiber, pendingProps, expirationTime); + clone.index = 0; + clone.sibling = null; + return clone; + } + + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; + if (!shouldTrackSideEffects) { + // Noop. + return lastPlacedIndex; + } + var current$$1 = newFiber.alternate; + if (current$$1 !== null) { + var oldIndex = current$$1.index; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.effectTag = Placement; + return lastPlacedIndex; + } + } + + function placeSingleChild(newFiber) { + // This is simpler for the single child case. We only need to do a + // placement for inserting new children. + if (shouldTrackSideEffects && newFiber.alternate === null) { + newFiber.effectTag = Placement; + } + return newFiber; + } + + function updateTextNode(returnFiber, current$$1, textContent, expirationTime) { + if (current$$1 === null || current$$1.tag !== HostText) { + // Insert + var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function updateElement(returnFiber, current$$1, element, expirationTime) { + if (current$$1 !== null && current$$1.elementType === element.type) { + // Move based on index + var existing = useFiber(current$$1, element.props, expirationTime); + existing.ref = coerceRef(returnFiber, current$$1, element); + existing.return = returnFiber; + return existing; + } else { + // Insert + var created = createFiberFromElement(element, returnFiber.mode, expirationTime); + created.ref = coerceRef(returnFiber, current$$1, element); + created.return = returnFiber; + return created; + } + } + + function updatePortal(returnFiber, current$$1, portal, expirationTime) { + if (current$$1 === null || current$$1.tag !== HostPortal || current$$1.stateNode.containerInfo !== portal.containerInfo || current$$1.stateNode.implementation !== portal.implementation) { + // Insert + var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, portal.children || [], expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function updateFragment(returnFiber, current$$1, fragment, expirationTime, key) { + if (current$$1 === null || current$$1.tag !== Fragment) { + // Insert + var created = createFiberFromFragment(fragment, returnFiber.mode, expirationTime, key); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current$$1, fragment, expirationTime); + existing.return = returnFiber; + return existing; + } + } + + function createChild(returnFiber, newChild, expirationTime) { + if (typeof newChild === 'string' || typeof newChild === 'number') { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + var created = createFiberFromText('' + newChild, returnFiber.mode, expirationTime); + created.return = returnFiber; + return created; + } + + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + var _created = createFiberFromElement(newChild, returnFiber.mode, expirationTime); + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; + } + case REACT_PORTAL_TYPE: + { + var _created2 = createFiberFromPortal(newChild, returnFiber.mode, expirationTime); + _created2.return = returnFiber; + return _created2; + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment(newChild, returnFiber.mode, expirationTime, null); + _created3.return = returnFiber; + return _created3; + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + return null; + } + + function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { + // Update the fiber if the keys match, otherwise return null. + + var key = oldFiber !== null ? oldFiber.key : null; + + if (typeof newChild === 'string' || typeof newChild === 'number') { + // Text nodes don't have keys. If the previous node is implicitly keyed + // we can continue to replace it without aborting even if it is not a text + // node. + if (key !== null) { + return null; + } + return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); + } + + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + if (newChild.key === key) { + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key); + } + return updateElement(returnFiber, oldFiber, newChild, expirationTime); + } else { + return null; + } + } + case REACT_PORTAL_TYPE: + { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, expirationTime); + } else { + return null; + } + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } + + return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + return null; + } + + function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { + if (typeof newChild === 'string' || typeof newChild === 'number') { + // Text nodes don't have keys, so we neither have to check the old nor + // new node for the key. If both are text nodes, they match. + var matchedFiber = existingChildren.get(newIdx) || null; + return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); + } + + if (typeof newChild === 'object' && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + { + var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; + if (newChild.type === REACT_FRAGMENT_TYPE) { + return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); + } + return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); + } + case REACT_PORTAL_TYPE: + { + var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; + return updatePortal(returnFiber, _matchedFiber2, newChild, expirationTime); + } + } + + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; + return updateFragment(returnFiber, _matchedFiber3, newChild, expirationTime, null); + } + + throwOnInvalidObjectType(returnFiber, newChild); + } + + return null; + } + + /** + * Warns if there is a duplicate or missing key + */ + function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) { + // This algorithm can't optimize by searching from both ends since we + // don't have backpointers on fibers. I'm trying to see how far we can get + // with that model. If it ends up not being worth the tradeoffs, we can + // add it later. + + // Even with a two ended optimization, we'd want to optimize for the case + // where there are few changes and brute force the comparison instead of + // going for the Map. It'd like to explore hitting that path first in + // forward-only mode and only go for the Map once we notice that we need + // lots of look ahead. This doesn't handle reversal as well as two ended + // search but that's unusual. Besides, for the two ended optimization to + // work on Iterables, we'd need to copy the whole set. + + // In this first iteration, we'll just live with hitting the bad case + // (adding everything to a Map) in for every insert/move. + + // If you change this code, also update reconcileChildrenIterator() which + // uses the same algorithm. + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (oldFiber === null) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime); + if (!_newFiber) { + continue; + } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } + previousNewFiber = _newFiber; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); + if (_newFiber2) { + if (shouldTrackSideEffects) { + if (_newFiber2.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete(_newFiber2.key === null ? newIdx : _newFiber2.key); + } + } + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; + } + previousNewFiber = _newFiber2; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function (child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + + var iteratorFn = getIteratorFn(newChildrenIterable); + !(typeof iteratorFn === 'function') ? reactProdInvariant('150') : void 0; + + var newChildren = iteratorFn.call(newChildrenIterable); + !(newChildren != null) ? reactProdInvariant('151') : void 0; + + var resultingFirstChild = null; + var previousNewFiber = null; + + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + + var step = newChildren.next(); + for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } + var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime); + if (newFiber === null) { + // TODO: This breaks on empty slots like null children. That's + // unfortunate because it triggers the slow path all the time. We need + // a better way to communicate whether this was a miss or null, + // boolean, undefined, etc. + if (!oldFiber) { + oldFiber = nextOldFiber; + } + break; + } + if (shouldTrackSideEffects) { + if (oldFiber && newFiber.alternate === null) { + // We matched the slot, but we didn't reuse the existing fiber, so we + // need to delete the existing child. + deleteChild(returnFiber, oldFiber); + } + } + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = newFiber; + } else { + // TODO: Defer siblings if we're not at the right index for this slot. + // I.e. if we had null values before, then we want to defer this + // for each null value. However, we also don't want to call updateSlot + // with the previous one. + previousNewFiber.sibling = newFiber; + } + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } + + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); + return resultingFirstChild; + } + + if (oldFiber === null) { + // If we don't have any more existing children we can choose a fast path + // since the rest will all be insertions. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber3 = createChild(returnFiber, step.value, expirationTime); + if (_newFiber3 === null) { + continue; + } + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; + } else { + previousNewFiber.sibling = _newFiber3; + } + previousNewFiber = _newFiber3; + } + return resultingFirstChild; + } + + // Add all children to a key map for quick lookups. + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); + + // Keep scanning and use the map to restore deleted items as moves. + for (; !step.done; newIdx++, step = newChildren.next()) { + var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); + if (_newFiber4 !== null) { + if (shouldTrackSideEffects) { + if (_newFiber4.alternate !== null) { + // The new fiber is a work in progress, but if there exists a + // current, that means that we reused the fiber. We need to delete + // it from the child list so that we don't add it to the deletion + // list. + existingChildren.delete(_newFiber4.key === null ? newIdx : _newFiber4.key); + } + } + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; + } + previousNewFiber = _newFiber4; + } + } + + if (shouldTrackSideEffects) { + // Any existing children that weren't consumed above were deleted. We need + // to add them to the deletion list. + existingChildren.forEach(function (child) { + return deleteChild(returnFiber, child); + }); + } + + return resultingFirstChild; + } + + function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) { + // There's no need to check for keys on text nodes since we don't have a + // way to define them. + if (currentFirstChild !== null && currentFirstChild.tag === HostText) { + // We already have an existing node so let's just update it and delete + // the rest. + deleteRemainingChildren(returnFiber, currentFirstChild.sibling); + var existing = useFiber(currentFirstChild, textContent, expirationTime); + existing.return = returnFiber; + return existing; + } + // The existing first child is not a text node so we need to create one + // and delete the existing ones. + deleteRemainingChildren(returnFiber, currentFirstChild); + var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); + created.return = returnFiber; + return created; + } + + function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) { + var key = element.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.elementType === element.type) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime); + existing.ref = coerceRef(returnFiber, child, element); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment(element.props.children, returnFiber.mode, expirationTime, element.key); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement(element, returnFiber.mode, expirationTime); + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } + } + + function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) { + var key = portal.key; + var child = currentFirstChild; + while (child !== null) { + // TODO: If key === null and child.key === null, then this only applies to + // the first item in the list. + if (child.key === key) { + if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, portal.children || [], expirationTime); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; + } + } else { + deleteChild(returnFiber, child); + } + child = child.sibling; + } + + var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); + created.return = returnFiber; + return created; + } + + // This API will tag the children with the side-effect of the reconciliation + // itself. They will be added to the side-effect list as we pass through the + // children and the parent. + function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) { + // This function is not recursive. + // If the top level item is an array, we treat it as a set of children, + // not as a fragment. Nested arrays on the other hand will be treated as + // fragment nodes. Recursion happens at the normal flow. + + // Handle top level unkeyed fragments as if they were arrays. + // This leads to an ambiguity between <>{[...]}</> and <>...</>. + // We treat the ambiguous cases above the same. + var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } + + // Handle object types + var isObject = typeof newChild === 'object' && newChild !== null; + + if (isObject) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime)); + case REACT_PORTAL_TYPE: + return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); + } + } + + if (typeof newChild === 'string' || typeof newChild === 'number') { + return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); + } + + if (isArray(newChild)) { + return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); + } + + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); + } + + if (isObject) { + throwOnInvalidObjectType(returnFiber, newChild); + } + + if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) { + // If the new child is undefined, and the return fiber is a composite + // component, throw an error. If Fiber return types are disabled, + // we already threw above. + switch (returnFiber.tag) { + case ClassComponent: + { + + } + // Intentionally fall through to the next case, which handles both + // functions and classes + // eslint-disable-next-lined no-fallthrough + case FunctionComponent: + { + var Component = returnFiber.type; + reactProdInvariant('152', Component.displayName || Component.name || 'Component'); + } + } + } + + // Remaining cases are all treated as empty. + return deleteRemainingChildren(returnFiber, currentFirstChild); + } + + return reconcileChildFibers; +} + +var reconcileChildFibers = ChildReconciler(true); +var mountChildFibers = ChildReconciler(false); + +function cloneChildFibers(current$$1, workInProgress) { + !(current$$1 === null || workInProgress.child === current$$1.child) ? reactProdInvariant('153') : void 0; + + if (workInProgress.child === null) { + return; + } + + var currentChild = workInProgress.child; + var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); + workInProgress.child = newChild; + + newChild.return = workInProgress; + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); + newChild.return = workInProgress; + } + newChild.sibling = null; +} + +var NO_CONTEXT$1 = {}; + +var contextStackCursor$1 = createCursor(NO_CONTEXT$1); +var contextFiberStackCursor = createCursor(NO_CONTEXT$1); +var rootInstanceStackCursor = createCursor(NO_CONTEXT$1); + +function requiredContext(c) { + !(c !== NO_CONTEXT$1) ? reactProdInvariant('174') : void 0; + return c; +} + +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} + +function pushHostContainer(fiber, nextRootInstance) { + // Push current root instance onto the stack; + // This allows us to reset root when portals are popped. + push(rootInstanceStackCursor, nextRootInstance, fiber); + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + + // Finally, we need to push the host context to the stack. + // However, we can't just call getRootHostContext() and push it because + // we'd have a different number of entries on the stack depending on + // whether getRootHostContext() throws somewhere in renderer code or not. + // So we push an empty value first. This lets us safely unwind on errors. + push(contextStackCursor$1, NO_CONTEXT$1, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); + // Now that we know this function doesn't throw, replace it. + pop(contextStackCursor$1, fiber); + push(contextStackCursor$1, nextRootContext, fiber); +} + +function popHostContainer(fiber) { + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} + +function getHostContext() { + var context = requiredContext(contextStackCursor$1.current); + return context; +} + +function pushHostContext(fiber) { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + var context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContext(context, fiber.type, rootInstance); + + // Don't push this Fiber's context unless it's unique. + if (context === nextContext) { + return; + } + + // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor$1, nextContext, fiber); +} + +function popHostContext(fiber) { + // Do not pop unless this Fiber provided the current context. + // pushHostContext() only pushes Fibers that provide unique contexts. + if (contextFiberStackCursor.current !== fiber) { + return; + } + + pop(contextStackCursor$1, fiber); + pop(contextFiberStackCursor, fiber); +} + +var NoEffect$1 = /* */0; +var UnmountSnapshot = /* */2; +var UnmountMutation = /* */4; +var MountMutation = /* */8; +var UnmountLayout = /* */16; +var MountLayout = /* */32; +var MountPassive = /* */64; +var UnmountPassive = /* */128; + +var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; + + +// These are set right before calling the component. +var renderExpirationTime = NoWork; +// The work-in-progress fiber. I've named it differently to distinguish it from +// the work-in-progress hook. +var currentlyRenderingFiber$1 = null; + +// Hooks are stored as a linked list on the fiber's memoizedState field. The +// current hook list is the list that belongs to the current fiber. The +// work-in-progress hook list is a new list that will be added to the +// work-in-progress fiber. +var currentHook = null; +var nextCurrentHook = null; +var firstWorkInProgressHook = null; +var workInProgressHook = null; +var nextWorkInProgressHook = null; + +var remainingExpirationTime = NoWork; +var componentUpdateQueue = null; +var sideEffectTag = 0; + +// Updates scheduled during render will trigger an immediate re-render at the +// end of the current pass. We can't store these updates on the normal queue, +// because if the work is aborted, they should be discarded. Because this is +// a relatively rare case, we also don't want to add an additional field to +// either the hook or queue object types. So we store them in a lazily create +// map of queue -> render-phase updates, which are discarded once the component +// completes without re-rendering. + +// Whether an update was scheduled during the currently executing render pass. +var didScheduleRenderPhaseUpdate = false; +// Lazily created map of render-phase updates +var renderPhaseUpdates = null; +// Counter to prevent infinite loops. +var numberOfReRenders = 0; +var RE_RENDER_LIMIT = 25; + +function throwInvalidHookError() { + reactProdInvariant('321'); +} + +function areHookInputsEqual(nextDeps, prevDeps) { + if (prevDeps === null) { + return false; + } + + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { + if (is(nextDeps[i], prevDeps[i])) { + continue; + } + return false; + } + return true; +} + +function renderWithHooks(current, workInProgress, Component, props, refOrContext, nextRenderExpirationTime) { + renderExpirationTime = nextRenderExpirationTime; + currentlyRenderingFiber$1 = workInProgress; + nextCurrentHook = current !== null ? current.memoizedState : null; + + { + ReactCurrentDispatcher$1.current = nextCurrentHook === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; + } + + var children = Component(props, refOrContext); + + if (didScheduleRenderPhaseUpdate) { + do { + didScheduleRenderPhaseUpdate = false; + numberOfReRenders += 1; + + // Start over from the beginning of the list + nextCurrentHook = current !== null ? current.memoizedState : null; + nextWorkInProgressHook = firstWorkInProgressHook; + + currentHook = null; + workInProgressHook = null; + componentUpdateQueue = null; + + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate; + + children = Component(props, refOrContext); + } while (didScheduleRenderPhaseUpdate); + + renderPhaseUpdates = null; + numberOfReRenders = 0; + } + + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + var renderedWork = currentlyRenderingFiber$1; + + renderedWork.memoizedState = firstWorkInProgressHook; + renderedWork.expirationTime = remainingExpirationTime; + renderedWork.updateQueue = componentUpdateQueue; + renderedWork.effectTag |= sideEffectTag; + + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + + renderExpirationTime = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + // These were reset above + // didScheduleRenderPhaseUpdate = false; + // renderPhaseUpdates = null; + // numberOfReRenders = 0; + + !!didRenderTooFewHooks ? reactProdInvariant('300') : void 0; + + return children; +} + +function bailoutHooks(current, workInProgress, expirationTime) { + workInProgress.updateQueue = current.updateQueue; + workInProgress.effectTag &= ~(Passive | Update); + if (current.expirationTime <= expirationTime) { + current.expirationTime = NoWork; + } +} + +function resetHooks() { + // We can assume the previous dispatcher is always this one, since we set it + // at the beginning of the render phase and there's no re-entrancy. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; + + // This is used to reset the state of this module when a component throws. + // It's also called inside mountIndeterminateComponent if we determine the + // component is a module-style component. + renderExpirationTime = NoWork; + currentlyRenderingFiber$1 = null; + + currentHook = null; + nextCurrentHook = null; + firstWorkInProgressHook = null; + workInProgressHook = null; + nextWorkInProgressHook = null; + + remainingExpirationTime = NoWork; + componentUpdateQueue = null; + sideEffectTag = 0; + + didScheduleRenderPhaseUpdate = false; + renderPhaseUpdates = null; + numberOfReRenders = 0; +} + +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + + baseState: null, + queue: null, + baseUpdate: null, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list + firstWorkInProgressHook = workInProgressHook = hook; + } else { + // Append to the end of the list + workInProgressHook = workInProgressHook.next = hook; + } + return workInProgressHook; +} + +function updateWorkInProgressHook() { + // This function is used both for updates and for re-renders triggered by a + // render phase update. It assumes there is either a current hook we can + // clone, or a work-in-progress hook from a previous render pass that we can + // use as a base. When we reach the end of the base list, we must switch to + // the dispatcher used for mounts. + if (nextWorkInProgressHook !== null) { + // There's already a work-in-progress. Reuse it. + workInProgressHook = nextWorkInProgressHook; + nextWorkInProgressHook = workInProgressHook.next; + + currentHook = nextCurrentHook; + nextCurrentHook = currentHook !== null ? currentHook.next : null; + } else { + // Clone from the current hook. + !(nextCurrentHook !== null) ? reactProdInvariant('310') : void 0; + currentHook = nextCurrentHook; + + var newHook = { + memoizedState: currentHook.memoizedState, + + baseState: currentHook.baseState, + queue: currentHook.queue, + baseUpdate: currentHook.baseUpdate, + + next: null + }; + + if (workInProgressHook === null) { + // This is the first hook in the list. + workInProgressHook = firstWorkInProgressHook = newHook; + } else { + // Append to the end of the list. + workInProgressHook = workInProgressHook.next = newHook; + } + nextCurrentHook = currentHook.next; + } + return workInProgressHook; +} + +function createFunctionComponentUpdateQueue() { + return { + lastEffect: null + }; +} + +function basicStateReducer(state, action) { + return typeof action === 'function' ? action(state) : action; +} + +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState = void 0; + if (init !== undefined) { + initialState = init(initialArg); + } else { + initialState = initialArg; + } + hook.memoizedState = hook.baseState = initialState; + var queue = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialState + }; + var dispatch = queue.dispatch = dispatchAction.bind(null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, queue); + return [hook.memoizedState, dispatch]; +} + +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; + !(queue !== null) ? reactProdInvariant('311') : void 0; + + queue.lastRenderedReducer = reducer; + + if (numberOfReRenders > 0) { + // This is a re-render. Apply the new render phase updates to the previous + var _dispatch = queue.dispatch; + if (renderPhaseUpdates !== null) { + // Render phase updates are stored in a map of queue -> linked list + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate !== undefined) { + renderPhaseUpdates.delete(queue); + var newState = hook.memoizedState; + var update = firstRenderPhaseUpdate; + do { + // Process this render phase update. We don't have to check the + // priority because it will always be the same as the current + // render's. + var _action = update.action; + newState = reducer(newState, _action); + update = update.next; + } while (update !== null); + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = newState; + // Don't persist the state accumlated from the render phase updates to + // the base state unless the queue is empty. + // TODO: Not sure if this is the desired semantics, but it's what we + // do for gDSFP. I can't remember why. + if (hook.baseUpdate === queue.last) { + hook.baseState = newState; + } + + queue.lastRenderedState = newState; + + return [newState, _dispatch]; + } + } + return [hook.memoizedState, _dispatch]; + } + + // The last update in the entire queue + var last = queue.last; + // The last update that is part of the base state. + var baseUpdate = hook.baseUpdate; + var baseState = hook.baseState; + + // Find the first unprocessed update. + var first = void 0; + if (baseUpdate !== null) { + if (last !== null) { + // For the first update, the queue is a circular linked list where + // `queue.last.next = queue.first`. Once the first update commits, and + // the `baseUpdate` is no longer empty, we can unravel the list. + last.next = null; + } + first = baseUpdate.next; + } else { + first = last !== null ? last.next : null; + } + if (first !== null) { + var _newState = baseState; + var newBaseState = null; + var newBaseUpdate = null; + var prevUpdate = baseUpdate; + var _update = first; + var didSkip = false; + do { + var updateExpirationTime = _update.expirationTime; + if (updateExpirationTime < renderExpirationTime) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + if (!didSkip) { + didSkip = true; + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + // Update the remaining priority in the queue. + if (updateExpirationTime > remainingExpirationTime) { + remainingExpirationTime = updateExpirationTime; + } + } else { + // Process this update. + if (_update.eagerReducer === reducer) { + // If this update was processed eagerly, and its reducer matches the + // current reducer, we can use the eagerly computed state. + _newState = _update.eagerState; + } else { + var _action2 = _update.action; + _newState = reducer(_newState, _action2); + } + } + prevUpdate = _update; + _update = _update.next; + } while (_update !== null && _update !== first); + + if (!didSkip) { + newBaseUpdate = prevUpdate; + newBaseState = _newState; + } + + // Mark that the fiber performed work, but only if the new state is + // different from the current state. + if (!is(_newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } + + hook.memoizedState = _newState; + hook.baseUpdate = newBaseUpdate; + hook.baseState = newBaseState; + + queue.lastRenderedState = _newState; + } + + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; +} + +function mountState(initialState) { + var hook = mountWorkInProgressHook(); + if (typeof initialState === 'function') { + initialState = initialState(); + } + hook.memoizedState = hook.baseState = initialState; + var queue = hook.queue = { + last: null, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState + }; + var dispatch = queue.dispatch = dispatchAction.bind(null, + // Flow doesn't know this is non-null, but we do. + currentlyRenderingFiber$1, queue); + return [hook.memoizedState, dispatch]; +} + +function updateState(initialState) { + return updateReducer(basicStateReducer, initialState); +} + +function pushEffect(tag, create, destroy, deps) { + var effect = { + tag: tag, + create: create, + destroy: destroy, + deps: deps, + // Circular + next: null + }; + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var _lastEffect = componentUpdateQueue.lastEffect; + if (_lastEffect === null) { + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var firstEffect = _lastEffect.next; + _lastEffect.next = effect; + effect.next = firstEffect; + componentUpdateQueue.lastEffect = effect; + } + } + return effect; +} + +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); + var ref = { current: initialValue }; + hook.memoizedState = ref; + return ref; +} + +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} + +function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); +} + +function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var destroy = undefined; + + if (currentHook !== null) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + if (nextDeps !== null) { + var prevDeps = prevEffect.deps; + if (areHookInputsEqual(nextDeps, prevDeps)) { + pushEffect(NoEffect$1, create, destroy, nextDeps); + return; + } + } + } + + sideEffectTag |= fiberEffectTag; + hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); +} + +function mountEffect(create, deps) { + return mountEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); +} + +function updateEffect(create, deps) { + return updateEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); +} + +function mountLayoutEffect(create, deps) { + return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps); +} + +function imperativeHandleEffect(create, ref) { + if (typeof ref === 'function') { + var refCallback = ref; + var _inst = create(); + refCallback(_inst); + return function () { + refCallback(null); + }; + } else if (ref !== null && ref !== undefined) { + var refObject = ref; + var _inst2 = create(); + refObject.current = _inst2; + return function () { + refObject.current = null; + }; + } +} + +function mountImperativeHandle(ref, create, deps) { + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return mountEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} + +function updateImperativeHandle(ref, create, deps) { + var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; + + return updateEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); +} + +function mountDebugValue(value, formatterFn) { + // This hook is normally a no-op. + // The react-debug-hooks package injects its own implementation + // so that e.g. DevTools can display custom hook values. +} + +var updateDebugValue = mountDebugValue; + +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + hook.memoizedState = [callback, nextDeps]; + return callback; +} + +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function updateMemo(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; + if (prevState !== null) { + // Assume these are defined. If they're not, areHookInputsEqual will warn. + if (nextDeps !== null) { + var prevDeps = prevState[1]; + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } + } + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} + +function dispatchAction(fiber, queue, action) { + !(numberOfReRenders < RE_RENDER_LIMIT) ? reactProdInvariant('301') : void 0; + + var alternate = fiber.alternate; + if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) { + // This is a render phase update. Stash it in a lazily-created map of + // queue -> linked list of updates. After this render pass, we'll restart + // and apply the stashed updates on top of the work-in-progress hook. + didScheduleRenderPhaseUpdate = true; + var update = { + expirationTime: renderExpirationTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + if (renderPhaseUpdates === null) { + renderPhaseUpdates = new Map(); + } + var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); + if (firstRenderPhaseUpdate === undefined) { + renderPhaseUpdates.set(queue, update); + } else { + // Append the update to the end of the list. + var lastRenderPhaseUpdate = firstRenderPhaseUpdate; + while (lastRenderPhaseUpdate.next !== null) { + lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; + } + lastRenderPhaseUpdate.next = update; + } + } else { + flushPassiveEffects$1(); + + var currentTime = requestCurrentTime(); + var _expirationTime = computeExpirationForFiber(currentTime, fiber); + + var _update2 = { + expirationTime: _expirationTime, + action: action, + eagerReducer: null, + eagerState: null, + next: null + }; + + // Append the update to the end of the list. + var _last = queue.last; + if (_last === null) { + // This is the first update. Create a circular list. + _update2.next = _update2; + } else { + var first = _last.next; + if (first !== null) { + // Still circular. + _update2.next = first; + } + _last.next = _update2; + } + queue.last = _update2; + + if (fiber.expirationTime === NoWork && (alternate === null || alternate.expirationTime === NoWork)) { + // The queue is currently empty, which means we can eagerly compute the + // next state before entering the render phase. If the new state is the + // same as the current state, we may be able to bail out entirely. + var _lastRenderedReducer = queue.lastRenderedReducer; + if (_lastRenderedReducer !== null) { + try { + var currentState = queue.lastRenderedState; + var _eagerState = _lastRenderedReducer(currentState, action); + // Stash the eagerly computed state, and the reducer used to compute + // it, on the update object. If the reducer hasn't changed by the + // time we enter the render phase, then the eager state can be used + // without calling the reducer again. + _update2.eagerReducer = _lastRenderedReducer; + _update2.eagerState = _eagerState; + if (is(_eagerState, currentState)) { + // Fast path. We can bail out without scheduling React to re-render. + // It's still possible that we'll need to rebase this update later, + // if the component re-renders for a different reason and by that + // time the reducer has changed. + return; + } + } catch (error) { + // Suppress the error. It will throw again in the render phase. + } finally { + + } + } + } + scheduleWork(fiber, _expirationTime); + } +} + +var ContextOnlyDispatcher = { + readContext: readContext, + + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError +}; + +var HooksDispatcherOnMount = { + readContext: readContext, + + useCallback: mountCallback, + useContext: readContext, + useEffect: mountEffect, + useImperativeHandle: mountImperativeHandle, + useLayoutEffect: mountLayoutEffect, + useMemo: mountMemo, + useReducer: mountReducer, + useRef: mountRef, + useState: mountState, + useDebugValue: mountDebugValue +}; + +var HooksDispatcherOnUpdate = { + readContext: readContext, + + useCallback: updateCallback, + useContext: readContext, + useEffect: updateEffect, + useImperativeHandle: updateImperativeHandle, + useLayoutEffect: updateLayoutEffect, + useMemo: updateMemo, + useReducer: updateReducer, + useRef: updateRef, + useState: updateState, + useDebugValue: updateDebugValue +}; + +var commitTime = 0; +var profilerStartTime = -1; + +function getCommitTime() { + return commitTime; +} + +function recordCommitTime() { + if (!enableProfilerTimer) { + return; + } + commitTime = now(); +} + +function startProfilerTimer(fiber) { + if (!enableProfilerTimer) { + return; + } + + profilerStartTime = now(); + + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now(); + } +} + +function stopProfilerTimerIfRunning(fiber) { + if (!enableProfilerTimer) { + return; + } + profilerStartTime = -1; +} + +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (!enableProfilerTimer) { + return; + } + + if (profilerStartTime >= 0) { + var elapsedTime = now() - profilerStartTime; + fiber.actualDuration += elapsedTime; + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; + } + profilerStartTime = -1; + } +} + +// The deepest Fiber on the stack involved in a hydration context. +// This may have been an insertion or a hydration. +var hydrationParentFiber = null; +var nextHydratableInstance = null; +var isHydrating = false; + +function enterHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = getFirstHydratableChild(parentInstance); + hydrationParentFiber = fiber; + isHydrating = true; + return true; +} + +function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + return false; + } + + var suspenseInstance = fiber.stateNode; + nextHydratableInstance = getNextHydratableSibling(suspenseInstance); + popToNextHostParent(fiber); + isHydrating = true; + return true; +} + +function deleteHydratableInstance(returnFiber, instance) { + var childToDelete = createFiberFromHostInstanceForDeletion(); + childToDelete.stateNode = instance; + childToDelete.return = returnFiber; + childToDelete.effectTag = Deletion; + + // This might seem like it belongs on progressedFirstDeletion. However, + // these children are not part of the reconciliation list of children. + // Even if we abort and rereconcile the children, that will try to hydrate + // again and the nodes are still in the host tree so these will be + // recreated. + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = childToDelete; + returnFiber.lastEffect = childToDelete; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; + } +} + +function insertNonHydratedInstance(returnFiber, fiber) { + fiber.effectTag |= Placement; + +} + +function tryHydrate(fiber, nextInstance) { + switch (fiber.tag) { + case HostComponent: + { + var type = fiber.type; + var props = fiber.pendingProps; + var instance = canHydrateInstance(nextInstance, type, props); + if (instance !== null) { + fiber.stateNode = instance; + return true; + } + return false; + } + case HostText: + { + var text = fiber.pendingProps; + var textInstance = canHydrateTextInstance(nextInstance, text); + if (textInstance !== null) { + fiber.stateNode = textInstance; + return true; + } + return false; + } + case SuspenseComponent: + { + if (enableSuspenseServerRenderer) { + var suspenseInstance = canHydrateSuspenseInstance(nextInstance); + if (suspenseInstance !== null) { + // Downgrade the tag to a dehydrated component until we've hydrated it. + fiber.tag = DehydratedSuspenseComponent; + fiber.stateNode = suspenseInstance; + return true; + } + } + return false; + } + default: + return false; + } +} + +function tryToClaimNextHydratableInstance(fiber) { + if (!isHydrating) { + return; + } + var nextInstance = nextHydratableInstance; + if (!nextInstance) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + var firstAttemptedInstance = nextInstance; + if (!tryHydrate(fiber, nextInstance)) { + // If we can't hydrate this instance let's try the next one. + // We use this as a heuristic. It's based on intuition and not data so it + // might be flawed or unnecessary. + nextInstance = getNextHydratableSibling(firstAttemptedInstance); + if (!nextInstance || !tryHydrate(fiber, nextInstance)) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + // We matched the next one, we'll now assume that the first one was + // superfluous and we'll delete it. Since we can't eagerly delete it + // we'll have to schedule a deletion. To do that, this node needs a dummy + // fiber associated with it. + deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); + } + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(nextInstance); +} + +function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) { + if (!supportsHydration) { + reactProdInvariant('175'); + } + + var instance = fiber.stateNode; + var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber); + // TODO: Type this specific to this type of component. + fiber.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. + if (updatePayload !== null) { + return true; + } + return false; +} + +function prepareToHydrateHostTextInstance(fiber) { + if (!supportsHydration) { + reactProdInvariant('176'); + } + + var textInstance = fiber.stateNode; + var textContent = fiber.memoizedProps; + var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); + return shouldUpdate; +} + +function skipPastDehydratedSuspenseInstance(fiber) { + if (!supportsHydration) { + reactProdInvariant('316'); + } + var suspenseInstance = fiber.stateNode; + !suspenseInstance ? reactProdInvariant('317') : void 0; + nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); +} + +function popToNextHostParent(fiber) { + var parent = fiber.return; + while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot && parent.tag !== DehydratedSuspenseComponent) { + parent = parent.return; + } + hydrationParentFiber = parent; +} + +function popHydrationState(fiber) { + if (!supportsHydration) { + return false; + } + if (fiber !== hydrationParentFiber) { + // We're deeper than the current hydration context, inside an inserted + // tree. + return false; + } + if (!isHydrating) { + // If we're not currently hydrating but we're in a hydration context, then + // we were an insertion and now need to pop up reenter hydration of our + // siblings. + popToNextHostParent(fiber); + isHydrating = true; + return false; + } + + var type = fiber.type; + + // If we have any remaining hydratable nodes, we need to delete them now. + // We only do this deeper than head and body since they tend to have random + // other nodes in them. We also ignore components with pure text content in + // side of them. + // TODO: Better heuristic. + if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { + var nextInstance = nextHydratableInstance; + while (nextInstance) { + deleteHydratableInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); + } + } + + popToNextHostParent(fiber); + nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null; + return true; +} + +function resetHydrationState() { + if (!supportsHydration) { + return; + } + + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; +} + +var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; + +var didReceiveUpdate = false; + + + +function reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime) { + if (current$$1 === null) { + // If this is a fresh new component that hasn't been rendered yet, we + // won't update its child set by applying minimal side-effects. Instead, + // we will add them all to the child before it gets rendered. That means + // we can optimize this reconciliation pass by not tracking side-effects. + workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); + } else { + // If the current child is the same as the work in progress, it means that + // we haven't yet started any work on these children. Therefore, we use + // the clone algorithm to create a copy of all the current children. + + // If we had any progressed work already, that is invalid at this point so + // let's throw it out. + workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, nextChildren, renderExpirationTime); + } +} + +function forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime) { + // This function is fork of reconcileChildren. It's used in cases where we + // want to reconcile without matching against the existing set. This has the + // effect of all current children being unmounted; even if the type and key + // are the same, the old child is unmounted and a new child is created. + // + // To do this, we're going to go through the reconcile algorithm twice. In + // the first pass, we schedule a deletion for all the current children by + // passing null. + workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, null, renderExpirationTime); + // In the second pass, we mount the new children. The trick here is that we + // pass null in place of where we usually pass the current child set. This has + // the effect of remounting all children regardless of whether their their + // identity matches. + workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); +} + +function updateForwardRef(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens after the first render suspends. + // We'll need to figure out if this is fine or can cause issues. + + var render = Component.render; + var ref = workInProgress.ref; + + // The rest is a fork of updateFunctionComponent + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + nextChildren = renderWithHooks(current$$1, workInProgress, render, nextProps, ref, renderExpirationTime); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + return workInProgress.child; +} + +function updateMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { + if (current$$1 === null) { + var type = Component.type; + if (isSimpleFunctionComponent(type) && Component.compare === null && + // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined) { + // If this is a plain function component without default props, + // and with only the default shallow comparison, we upgrade it + // to a SimpleMemoComponent to allow fast path updates. + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = type; + return updateSimpleMemoComponent(current$$1, workInProgress, type, nextProps, updateExpirationTime, renderExpirationTime); + } + var child = createFiberFromTypeAndProps(Component.type, null, nextProps, null, workInProgress.mode, renderExpirationTime); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } + var currentChild = current$$1.child; // This is always exactly one child + if (updateExpirationTime < renderExpirationTime) { + // This will be the props with resolved defaultProps, + // unlike current.memoizedProps which will be the unresolved ones. + var prevProps = currentChild.memoizedProps; + // Default to shallow comparison + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; + if (compare(prevProps, nextProps) && current$$1.ref === workInProgress.ref) { + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + var newChild = createWorkInProgress(currentChild, nextProps, renderExpirationTime); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} + +function updateSimpleMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { + // TODO: current can be non-null here even if the component + // hasn't yet mounted. This happens when the inner render suspends. + // We'll need to figure out if this is fine or can cause issues. + + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + if (shallowEqual(prevProps, nextProps) && current$$1.ref === workInProgress.ref) { + didReceiveUpdate = false; + if (updateExpirationTime < renderExpirationTime) { + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + } + } + return updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime); +} + +function updateFragment(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + return workInProgress.child; +} + +function updateMode(current$$1, workInProgress, renderExpirationTime) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + return workInProgress.child; +} + +function updateProfiler(current$$1, workInProgress, renderExpirationTime) { + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + return workInProgress.child; +} + +function markRef(current$$1, workInProgress) { + var ref = workInProgress.ref; + if (current$$1 === null && ref !== null || current$$1 !== null && current$$1.ref !== ref) { + // Schedule a Ref effect + workInProgress.effectTag |= Ref; + } +} + +function updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + var context = getMaskedContext(workInProgress, unmaskedContext); + + var nextChildren = void 0; + prepareToReadContext(workInProgress, renderExpirationTime); + { + nextChildren = renderWithHooks(current$$1, workInProgress, Component, nextProps, context, renderExpirationTime); + } + + if (current$$1 !== null && !didReceiveUpdate) { + bailoutHooks(current$$1, workInProgress, renderExpirationTime); + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + return workInProgress.child; +} + +function updateClassComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + var instance = workInProgress.stateNode; + var shouldUpdate = void 0; + if (instance === null) { + if (current$$1 !== null) { + // An class component without an instance only mounts if it suspended + // inside a non- concurrent tree, in an inconsistent state. We want to + // tree it like a new mount, even though an empty version of it already + // committed. Disconnect the alternate pointers. + current$$1.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + // In the initial pass we might need to construct the instance. + constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); + mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); + shouldUpdate = true; + } else if (current$$1 === null) { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); + } else { + shouldUpdate = updateClassInstance(current$$1, workInProgress, Component, nextProps, renderExpirationTime); + } + var nextUnitOfWork = finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime); + return nextUnitOfWork; +} + +function finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime) { + // Refs should update even if shouldComponentUpdate returns false + markRef(current$$1, workInProgress); + + var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; + + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); + } + + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + + var instance = workInProgress.stateNode; + + // Rerender + ReactCurrentOwner$2.current = workInProgress; + var nextChildren = void 0; + if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') { + // If we captured an error, but getDerivedStateFrom catch is not defined, + // unmount all the children. componentDidCatch will schedule an update to + // re-render a fallback. This is temporary until we migrate everyone to + // the new API. + // TODO: Warn in a future release. + nextChildren = null; + + if (enableProfilerTimer) { + stopProfilerTimerIfRunning(workInProgress); + } + } else { + { + nextChildren = instance.render(); + } + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + if (current$$1 !== null && didCaptureError) { + // If we're recovering from an error, reconcile without reusing any of + // the existing children. Conceptually, the normal children and the children + // that are shown on error are two different sets, so we shouldn't reuse + // normal children even if their identities match. + forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime); + } else { + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + } + + // Memoize state using the values we just used to render. + // TODO: Restructure so we never read values from the instance. + workInProgress.memoizedState = instance.state; + + // The context might have changed so we need to recalculate it. + if (hasContext) { + invalidateContextProvider(workInProgress, Component, true); + } + + return workInProgress.child; +} + +function pushHostRootContext(workInProgress) { + var root = workInProgress.stateNode; + if (root.pendingContext) { + pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); + } else if (root.context) { + // Should always be set + pushTopLevelContextObject(workInProgress, root.context, false); + } + pushHostContainer(workInProgress, root.containerInfo); +} + +function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { + pushHostRootContext(workInProgress); + var updateQueue = workInProgress.updateQueue; + !(updateQueue !== null) ? reactProdInvariant('282') : void 0; + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState !== null ? prevState.element : null; + processUpdateQueue(workInProgress, updateQueue, nextProps, null, renderExpirationTime); + var nextState = workInProgress.memoizedState; + // Caution: React DevTools currently depends on this property + // being called "element". + var nextChildren = nextState.element; + if (nextChildren === prevChildren) { + // If the state is the same as before, that's a bailout because we had + // no work that expires at this time. + resetHydrationState(); + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + var root = workInProgress.stateNode; + if ((current$$1 === null || current$$1.child === null) && root.hydrate && enterHydrationState(workInProgress)) { + // If we don't have any current children this might be the first pass. + // We always try to hydrate. If this isn't a hydration pass there won't + // be any children to hydrate which is effectively the same thing as + // not hydrating. + + // This is a bit of a hack. We track the host root as a placement to + // know that we're currently in a mounting state. That way isMounted + // works as expected. We must reset this before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag |= Placement; + + // Ensure that children mount into this root without tracking + // side-effects. This ensures that we don't store Placement effects on + // nodes that will be hydrated. + workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); + } else { + // Otherwise reset hydration state in case we aborted and resumed another + // root. + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + resetHydrationState(); + } + return workInProgress.child; +} + +function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { + pushHostContext(workInProgress); + + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var nextProps = workInProgress.pendingProps; + var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; + + var nextChildren = nextProps.children; + var isDirectTextChild = shouldSetTextContent(type, nextProps); + + if (isDirectTextChild) { + // We special case a direct text child of a host node. This is a common + // case. We won't handle it as a reified child. We will instead handle + // this in the host environment that also have access to this prop. That + // avoids allocating another HostText fiber and traversing it. + nextChildren = null; + } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { + // If we're switching from a direct text child to a normal child, or to + // empty, we need to schedule the text content to be reset. + workInProgress.effectTag |= ContentReset; + } + + markRef(current$$1, workInProgress); + + // Check the host config to see if the children are offscreen/hidden. + if (renderExpirationTime !== Never && workInProgress.mode & ConcurrentMode && shouldDeprioritizeSubtree(type, nextProps)) { + // Schedule this fiber to re-render at offscreen priority. Then bailout. + workInProgress.expirationTime = workInProgress.childExpirationTime = Never; + return null; + } + + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + return workInProgress.child; +} + +function updateHostText(current$$1, workInProgress) { + if (current$$1 === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + return null; +} + +function mountLazyComponent(_current, workInProgress, elementType, updateExpirationTime, renderExpirationTime) { + if (_current !== null) { + // An lazy component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + // We can't start a User Timing measurement with correct label yet. + // Cancel and resume right after we know the tag. + cancelWorkTimer(workInProgress); + var Component = readLazyComponentType(elementType); + // Store the unwrapped component in the type. + workInProgress.type = Component; + var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component); + startWorkTimer(workInProgress); + var resolvedProps = resolveDefaultProps(Component, props); + var child = void 0; + switch (resolvedTag) { + case FunctionComponent: + { + child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); + break; + } + case ClassComponent: + { + child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); + break; + } + case ForwardRef: + { + child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderExpirationTime); + break; + } + case MemoComponent: + { + child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too + updateExpirationTime, renderExpirationTime); + break; + } + default: + { + var hint = ''; + reactProdInvariant('306', Component, hint); + } + } + return child; +} + +function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderExpirationTime) { + if (_current !== null) { + // An incomplete component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + // Promote the fiber to a class and try rendering again. + workInProgress.tag = ClassComponent; + + // The rest of this function is a fork of `updateClassComponent` + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = void 0; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + prepareToReadContext(workInProgress, renderExpirationTime); + + constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); + mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); + + return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); +} + +function mountIndeterminateComponent(_current, workInProgress, Component, renderExpirationTime) { + if (_current !== null) { + // An indeterminate component only mounts if it suspended inside a non- + // concurrent tree, in an inconsistent state. We want to treat it like + // a new mount, even though an empty version of it already committed. + // Disconnect the alternate pointers. + _current.alternate = null; + workInProgress.alternate = null; + // Since this is conceptually a new fiber, schedule a Placement effect + workInProgress.effectTag |= Placement; + } + + var props = workInProgress.pendingProps; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); + var context = getMaskedContext(workInProgress, unmaskedContext); + + prepareToReadContext(workInProgress, renderExpirationTime); + + var value = void 0; + + { + value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime); + } + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + + if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { + // Proceed under the assumption that this is a class instance + workInProgress.tag = ClassComponent; + + // Throw out any hooks that were used. + resetHooks(); + + // Push context providers early to prevent context stack mismatches. + // During mounting we don't know the child context yet as the instance doesn't exist. + // We will invalidate the child context in finishClassComponent() right after rendering. + var hasContext = false; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null; + + var getDerivedStateFromProps = Component.getDerivedStateFromProps; + if (typeof getDerivedStateFromProps === 'function') { + applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props); + } + + adoptClassInstance(workInProgress, value); + mountClassInstance(workInProgress, Component, props, renderExpirationTime); + return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); + } else { + // Proceed under the assumption that this is a function component + workInProgress.tag = FunctionComponent; + reconcileChildren(null, workInProgress, value, renderExpirationTime); + return workInProgress.child; + } +} + +function updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { + var mode = workInProgress.mode; + var nextProps = workInProgress.pendingProps; + + // We should attempt to render the primary children unless this boundary + // already suspended during this render (`alreadyCaptured` is true). + var nextState = workInProgress.memoizedState; + + var nextDidTimeout = void 0; + if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This is the first attempt. + nextState = null; + nextDidTimeout = false; + } else { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + nextState = { + timedOutAt: nextState !== null ? nextState.timedOutAt : NoWork + }; + nextDidTimeout = true; + workInProgress.effectTag &= ~DidCapture; + } + + // This next part is a bit confusing. If the children timeout, we switch to + // showing the fallback children in place of the "primary" children. + // However, we don't want to delete the primary children because then their + // state will be lost (both the React state and the host state, e.g. + // uncontrolled form inputs). Instead we keep them mounted and hide them. + // Both the fallback children AND the primary children are rendered at the + // same time. Once the primary children are un-suspended, we can delete + // the fallback children — don't need to preserve their state. + // + // The two sets of children are siblings in the host environment, but + // semantically, for purposes of reconciliation, they are two separate sets. + // So we store them using two fragment fibers. + // + // However, we want to avoid allocating extra fibers for every placeholder. + // They're only necessary when the children time out, because that's the + // only time when both sets are mounted. + // + // So, the extra fragment fibers are only used if the children time out. + // Otherwise, we render the primary children directly. This requires some + // custom reconciliation logic to preserve the state of the primary + // children. It's essentially a very basic form of re-parenting. + + // `child` points to the child fiber. In the normal case, this is the first + // fiber of the primary children set. In the timed-out case, it's a + // a fragment fiber containing the primary children. + var child = void 0; + // `next` points to the next fiber React should render. In the normal case, + // it's the same as `child`: the first fiber of the primary children set. + // In the timed-out case, it's a fragment fiber containing the *fallback* + // children -- we skip over the primary children entirely. + var next = void 0; + if (current$$1 === null) { + if (enableSuspenseServerRenderer) { + // If we're currently hydrating, try to hydrate this boundary. + // But only if this has a fallback. + if (nextProps.fallback !== undefined) { + tryToClaimNextHydratableInstance(workInProgress); + // This could've changed the tag if this was a dehydrated suspense component. + if (workInProgress.tag === DehydratedSuspenseComponent) { + return updateDehydratedSuspenseComponent(null, workInProgress, renderExpirationTime); + } + } + } + + // This is the initial mount. This branch is pretty simple because there's + // no previous state that needs to be preserved. + if (nextDidTimeout) { + // Mount separate fragments for primary and fallback children. + var nextFallbackChildren = nextProps.fallback; + var primaryChildFragment = createFiberFromFragment(null, mode, NoWork, null); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var progressedState = workInProgress.memoizedState; + var progressedPrimaryChild = progressedState !== null ? workInProgress.child.child : workInProgress.child; + primaryChildFragment.child = progressedPrimaryChild; + } + + var fallbackChildFragment = createFiberFromFragment(nextFallbackChildren, mode, renderExpirationTime, null); + primaryChildFragment.sibling = fallbackChildFragment; + child = primaryChildFragment; + // Skip the primary children, and continue working on the + // fallback children. + next = fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // Mount the primary children without an intermediate fragment fiber. + var nextPrimaryChildren = nextProps.children; + child = next = mountChildFibers(workInProgress, null, nextPrimaryChildren, renderExpirationTime); + } + } else { + // This is an update. This branch is more complicated because we need to + // ensure the state of the primary children is preserved. + var prevState = current$$1.memoizedState; + var prevDidTimeout = prevState !== null; + if (prevDidTimeout) { + // The current tree already timed out. That means each child set is + var currentPrimaryChildFragment = current$$1.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + if (nextDidTimeout) { + // Still timed out. Reuse the current primary children by cloning + // its fragment. We're going to skip over these entirely. + var _nextFallbackChildren = nextProps.fallback; + var _primaryChildFragment = createWorkInProgress(currentPrimaryChildFragment, currentPrimaryChildFragment.pendingProps, NoWork); + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState = workInProgress.memoizedState; + var _progressedPrimaryChild = _progressedState !== null ? workInProgress.child.child : workInProgress.child; + if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { + _primaryChildFragment.child = _progressedPrimaryChild; + } + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var treeBaseDuration = 0; + var hiddenChild = _primaryChildFragment.child; + while (hiddenChild !== null) { + treeBaseDuration += hiddenChild.treeBaseDuration; + hiddenChild = hiddenChild.sibling; + } + _primaryChildFragment.treeBaseDuration = treeBaseDuration; + } + + // Clone the fallback child fragment, too. These we'll continue + // working on. + var _fallbackChildFragment = _primaryChildFragment.sibling = createWorkInProgress(currentFallbackChildFragment, _nextFallbackChildren, currentFallbackChildFragment.expirationTime); + child = _primaryChildFragment; + _primaryChildFragment.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment; + child.return = next.return = workInProgress; + } else { + // No longer suspended. Switch back to showing the primary children, + // and remove the intermediate fragment fiber. + var _nextPrimaryChildren = nextProps.children; + var currentPrimaryChild = currentPrimaryChildFragment.child; + var primaryChild = reconcileChildFibers(workInProgress, currentPrimaryChild, _nextPrimaryChildren, renderExpirationTime); + + // If this render doesn't suspend, we need to delete the fallback + // children. Wait until the complete phase, after we've confirmed the + // fallback is no longer needed. + // TODO: Would it be better to store the fallback fragment on + // the stateNode? + + // Continue rendering the children, like we normally do. + child = next = primaryChild; + } + } else { + // The current tree has not already timed out. That means the primary + // children are not wrapped in a fragment fiber. + var _currentPrimaryChild = current$$1.child; + if (nextDidTimeout) { + // Timed out. Wrap the children in a fragment fiber to keep them + // separate from the fallback children. + var _nextFallbackChildren2 = nextProps.fallback; + var _primaryChildFragment2 = createFiberFromFragment( + // It shouldn't matter what the pending props are because we aren't + // going to render this fragment. + null, mode, NoWork, null); + _primaryChildFragment2.child = _currentPrimaryChild; + + // Even though we're creating a new fiber, there are no new children, + // because we're reusing an already mounted tree. So we don't need to + // schedule a placement. + // primaryChildFragment.effectTag |= Placement; + + if ((workInProgress.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, we commit the effects from the + var _progressedState2 = workInProgress.memoizedState; + var _progressedPrimaryChild2 = _progressedState2 !== null ? workInProgress.child.child : workInProgress.child; + _primaryChildFragment2.child = _progressedPrimaryChild2; + } + + // Because primaryChildFragment is a new fiber that we're inserting as the + // parent of a new tree, we need to set its treeBaseDuration. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // treeBaseDuration is the sum of all the child tree base durations. + var _treeBaseDuration = 0; + var _hiddenChild = _primaryChildFragment2.child; + while (_hiddenChild !== null) { + _treeBaseDuration += _hiddenChild.treeBaseDuration; + _hiddenChild = _hiddenChild.sibling; + } + _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; + } + + // Create a fragment from the fallback children, too. + var _fallbackChildFragment2 = _primaryChildFragment2.sibling = createFiberFromFragment(_nextFallbackChildren2, mode, renderExpirationTime, null); + _fallbackChildFragment2.effectTag |= Placement; + child = _primaryChildFragment2; + _primaryChildFragment2.childExpirationTime = NoWork; + // Skip the primary children, and continue working on the + // fallback children. + next = _fallbackChildFragment2; + child.return = next.return = workInProgress; + } else { + // Still haven't timed out. Continue rendering the children, like we + // normally do. + var _nextPrimaryChildren2 = nextProps.children; + next = child = reconcileChildFibers(workInProgress, _currentPrimaryChild, _nextPrimaryChildren2, renderExpirationTime); + } + } + workInProgress.stateNode = current$$1.stateNode; + } + + workInProgress.memoizedState = nextState; + workInProgress.child = child; + return next; +} + +function updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { + if (current$$1 === null) { + // During the first pass, we'll bail out and not drill into the children. + // Instead, we'll leave the content in place and try to hydrate it later. + workInProgress.expirationTime = Never; + return null; + } + // We use childExpirationTime to indicate that a child might depend on context, so if + // any context has changed, we need to treat is as if the input might have changed. + var hasContextChanged$$1 = current$$1.childExpirationTime >= renderExpirationTime; + if (didReceiveUpdate || hasContextChanged$$1) { + // This boundary has changed since the first render. This means that we are now unable to + // hydrate it. We might still be able to hydrate it using an earlier expiration time but + // during this render we can't. Instead, we're going to delete the whole subtree and + // instead inject a new real Suspense boundary to take its place, which may render content + // or fallback. The real Suspense boundary will suspend for a while so we have some time + // to ensure it can produce real content, but all state and pending events will be lost. + + // Detach from the current dehydrated boundary. + current$$1.alternate = null; + workInProgress.alternate = null; + + // Insert a deletion in the effect list. + var returnFiber = workInProgress.return; + !(returnFiber !== null) ? reactProdInvariant('315') : void 0; + var last = returnFiber.lastEffect; + if (last !== null) { + last.nextEffect = current$$1; + returnFiber.lastEffect = current$$1; + } else { + returnFiber.firstEffect = returnFiber.lastEffect = current$$1; + } + current$$1.nextEffect = null; + current$$1.effectTag = Deletion; + + // Upgrade this work in progress to a real Suspense component. + workInProgress.tag = SuspenseComponent; + workInProgress.stateNode = null; + workInProgress.memoizedState = null; + // This is now an insertion. + workInProgress.effectTag |= Placement; + // Retry as a real Suspense component. + return updateSuspenseComponent(null, workInProgress, renderExpirationTime); + } + if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This is the first attempt. + reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); + return workInProgress.child; + } else { + // Something suspended. Leave the existing children in place. + // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? + workInProgress.child = null; + return null; + } +} + +function updatePortalComponent(current$$1, workInProgress, renderExpirationTime) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; + if (current$$1 === null) { + // Portals are special because we don't append the children during mount + // but at commit. Therefore we need to track insertions which the normal + // flow doesn't do during mount. This doesn't happen at the root because + // the root always starts with a "current" with a null child. + // TODO: Consider unifying this with how the root works. + workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); + } else { + reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); + } + return workInProgress.child; +} + +function updateContextProvider(current$$1, workInProgress, renderExpirationTime) { + var providerType = workInProgress.type; + var context = providerType._context; + + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + + var newValue = newProps.value; + + pushProvider(workInProgress, newValue); + + if (oldProps !== null) { + var oldValue = oldProps.value; + var changedBits = calculateChangedBits(context, newValue, oldValue); + if (changedBits === 0) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children && !hasContextChanged()) { + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + } else { + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange(workInProgress, context, changedBits, renderExpirationTime); + } + } + + var newChildren = newProps.children; + reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); + return workInProgress.child; +} + +function updateContextConsumer(current$$1, workInProgress, renderExpirationTime) { + var context = workInProgress.type; + // The logic below for Context differs depending on PROD or DEV mode. In + // DEV mode, we create a separate object for Context.Consumer that acts + // like a proxy to Context. This proxy object adds unnecessary code in PROD + // so we use the old behaviour (Context.Consumer references Context) to + // reduce size and overhead. The separate object references context via + // a property called "_context", which also gives us the ability to check + // in DEV mode if this property exists or not and warn if it does not. + var newProps = workInProgress.pendingProps; + var render = newProps.children; + + prepareToReadContext(workInProgress, renderExpirationTime); + var newValue = readContext(context, newProps.unstable_observedBits); + var newChildren = void 0; + { + newChildren = render(newValue); + } + + // React DevTools reads this flag. + workInProgress.effectTag |= PerformedWork; + reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); + return workInProgress.child; +} + +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} + +function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) { + cancelWorkTimer(workInProgress); + + if (current$$1 !== null) { + // Reuse previous context list + workInProgress.contextDependencies = current$$1.contextDependencies; + } + + if (enableProfilerTimer) { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(workInProgress); + } + + // Check if the children have any pending work. + var childExpirationTime = workInProgress.childExpirationTime; + if (childExpirationTime < renderExpirationTime) { + // The children don't have any work either. We can skip them. + // TODO: Once we add back resuming, we should check if the children are + // a work-in-progress set. If so, we need to transfer their effects. + return null; + } else { + // This fiber doesn't have work, but its subtree does. Clone the child + // fibers and continue. + cloneChildFibers(current$$1, workInProgress); + return workInProgress.child; + } +} + +function beginWork(current$$1, workInProgress, renderExpirationTime) { + var updateExpirationTime = workInProgress.expirationTime; + + if (current$$1 !== null) { + var oldProps = current$$1.memoizedProps; + var newProps = workInProgress.pendingProps; + + if (oldProps !== newProps || hasContextChanged()) { + // If props or context changed, mark the fiber as having performed work. + // This may be unset if the props are determined to be equal later (memo). + didReceiveUpdate = true; + } else if (updateExpirationTime < renderExpirationTime) { + didReceiveUpdate = false; + // This fiber does not have any pending work. Bailout without entering + // the begin phase. There's still some bookkeeping we that needs to be done + // in this optimized path, mostly pushing stuff onto the stack. + switch (workInProgress.tag) { + case HostRoot: + pushHostRootContext(workInProgress); + resetHydrationState(); + break; + case HostComponent: + pushHostContext(workInProgress); + break; + case ClassComponent: + { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + pushContextProvider(workInProgress); + } + break; + } + case HostPortal: + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + break; + case ContextProvider: + { + var newValue = workInProgress.memoizedProps.value; + pushProvider(workInProgress, newValue); + break; + } + case Profiler: + if (enableProfilerTimer) { + workInProgress.effectTag |= Update; + } + break; + case SuspenseComponent: + { + var state = workInProgress.memoizedState; + var didTimeout = state !== null; + if (didTimeout) { + // If this boundary is currently timed out, we need to decide + // whether to retry the primary children, or to skip over it and + // go straight to the fallback. Check the priority of the primary + var primaryChildFragment = workInProgress.child; + var primaryChildExpirationTime = primaryChildFragment.childExpirationTime; + if (primaryChildExpirationTime !== NoWork && primaryChildExpirationTime >= renderExpirationTime) { + // The primary children have pending work. Use the normal path + // to attempt to render the primary children again. + return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); + } else { + // The primary children do not have pending work with sufficient + // priority. Bailout. + var child = bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; + } else { + return null; + } + } + } + break; + } + case DehydratedSuspenseComponent: + { + if (enableSuspenseServerRenderer) { + // We know that this component will suspend again because if it has + // been unsuspended it has committed as a regular Suspense component. + // If it needs to be retried, it should have work scheduled on it. + workInProgress.effectTag |= DidCapture; + break; + } + } + } + return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); + } + } else { + didReceiveUpdate = false; + } + + // Before entering the begin phase, clear the expiration time. + workInProgress.expirationTime = NoWork; + + switch (workInProgress.tag) { + case IndeterminateComponent: + { + var elementType = workInProgress.elementType; + return mountIndeterminateComponent(current$$1, workInProgress, elementType, renderExpirationTime); + } + case LazyComponent: + { + var _elementType = workInProgress.elementType; + return mountLazyComponent(current$$1, workInProgress, _elementType, updateExpirationTime, renderExpirationTime); + } + case FunctionComponent: + { + var _Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps); + return updateFunctionComponent(current$$1, workInProgress, _Component, resolvedProps, renderExpirationTime); + } + case ClassComponent: + { + var _Component2 = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; + var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps); + return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime); + } + case HostRoot: + return updateHostRoot(current$$1, workInProgress, renderExpirationTime); + case HostComponent: + return updateHostComponent(current$$1, workInProgress, renderExpirationTime); + case HostText: + return updateHostText(current$$1, workInProgress); + case SuspenseComponent: + return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); + case HostPortal: + return updatePortalComponent(current$$1, workInProgress, renderExpirationTime); + case ForwardRef: + { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; + var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2); + return updateForwardRef(current$$1, workInProgress, type, _resolvedProps2, renderExpirationTime); + } + case Fragment: + return updateFragment(current$$1, workInProgress, renderExpirationTime); + case Mode: + return updateMode(current$$1, workInProgress, renderExpirationTime); + case Profiler: + return updateProfiler(current$$1, workInProgress, renderExpirationTime); + case ContextProvider: + return updateContextProvider(current$$1, workInProgress, renderExpirationTime); + case ContextConsumer: + return updateContextConsumer(current$$1, workInProgress, renderExpirationTime); + case MemoComponent: + { + var _type2 = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; + // Resolve outer props first, then resolve inner props. + var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); + _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); + return updateMemoComponent(current$$1, workInProgress, _type2, _resolvedProps3, updateExpirationTime, renderExpirationTime); + } + case SimpleMemoComponent: + { + return updateSimpleMemoComponent(current$$1, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime); + } + case IncompleteClassComponent: + { + var _Component3 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; + var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4); + return mountIncompleteClassComponent(current$$1, workInProgress, _Component3, _resolvedProps4, renderExpirationTime); + } + case DehydratedSuspenseComponent: + { + if (enableSuspenseServerRenderer) { + return updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime); + } + break; + } + } + reactProdInvariant('156'); +} + +var valueCursor = createCursor(null); + +var currentlyRenderingFiber = null; +var lastContextDependency = null; +var lastContextWithAllBitsObserved = null; + +function resetContextDependences() { + // This is called right before React yields execution, to ensure `readContext` + // cannot be called outside the render phase. + currentlyRenderingFiber = null; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + +} + + + + + +function pushProvider(providerFiber, nextValue) { + var context = providerFiber.type._context; + + if (isPrimaryRenderer) { + push(valueCursor, context._currentValue, providerFiber); + + context._currentValue = nextValue; + + } else { + push(valueCursor, context._currentValue2, providerFiber); + + context._currentValue2 = nextValue; + + } +} + +function popProvider(providerFiber) { + var currentValue = valueCursor.current; + + pop(valueCursor, providerFiber); + + var context = providerFiber.type._context; + if (isPrimaryRenderer) { + context._currentValue = currentValue; + } else { + context._currentValue2 = currentValue; + } +} + +function calculateChangedBits(context, newValue, oldValue) { + if (is(oldValue, newValue)) { + // No change + return 0; + } else { + var changedBits = typeof context._calculateChangedBits === 'function' ? context._calculateChangedBits(oldValue, newValue) : maxSigned31BitInt; + + return changedBits | 0; + } +} + +function scheduleWorkOnParentPath(parent, renderExpirationTime) { + // Update the child expiration time of all the ancestors, including + // the alternates. + var node = parent; + while (node !== null) { + var alternate = node.alternate; + if (node.childExpirationTime < renderExpirationTime) { + node.childExpirationTime = renderExpirationTime; + if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { + alternate.childExpirationTime = renderExpirationTime; + } + } else if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { + alternate.childExpirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; + } + node = node.return; + } +} + +function propagateContextChange(workInProgress, context, changedBits, renderExpirationTime) { + var fiber = workInProgress.child; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } + while (fiber !== null) { + var nextFiber = void 0; + + // Visit this fiber. + var list = fiber.contextDependencies; + if (list !== null) { + nextFiber = fiber.child; + + var dependency = list.first; + while (dependency !== null) { + // Check if the context matches. + if (dependency.context === context && (dependency.observedBits & changedBits) !== 0) { + // Match! Schedule an update on this fiber. + + if (fiber.tag === ClassComponent) { + // Schedule a force update on the work-in-progress. + var update = createUpdate(renderExpirationTime); + update.tag = ForceUpdate; + // TODO: Because we don't have a work-in-progress, this will add the + // update to the current fiber, too, which means it will persist even if + // this render is thrown away. Since it's a race condition, not sure it's + // worth fixing. + enqueueUpdate(fiber, update); + } + + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var alternate = fiber.alternate; + if (alternate !== null && alternate.expirationTime < renderExpirationTime) { + alternate.expirationTime = renderExpirationTime; + } + + scheduleWorkOnParentPath(fiber.return, renderExpirationTime); + + // Mark the expiration time on the list, too. + if (list.expirationTime < renderExpirationTime) { + list.expirationTime = renderExpirationTime; + } + + // Since we already found a match, we can stop traversing the + // dependency list. + break; + } + dependency = dependency.next; + } + } else if (fiber.tag === ContextProvider) { + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + } else if (enableSuspenseServerRenderer && fiber.tag === DehydratedSuspenseComponent) { + // If a dehydrated suspense component is in this subtree, we don't know + // if it will have any context consumers in it. The best we can do is + // mark it as having updates on its children. + if (fiber.expirationTime < renderExpirationTime) { + fiber.expirationTime = renderExpirationTime; + } + var _alternate = fiber.alternate; + if (_alternate !== null && _alternate.expirationTime < renderExpirationTime) { + _alternate.expirationTime = renderExpirationTime; + } + // This is intentionally passing this fiber as the parent + // because we want to schedule this fiber as having work + // on its children. We'll use the childExpirationTime on + // this fiber to indicate that a context has changed. + scheduleWorkOnParentPath(fiber, renderExpirationTime); + nextFiber = fiber.sibling; + } else { + // Traverse down. + nextFiber = fiber.child; + } + + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber.return = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } + var sibling = nextFiber.sibling; + if (sibling !== null) { + // Set the return pointer of the sibling to the work-in-progress fiber. + sibling.return = nextFiber.return; + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber.return; + } + } + fiber = nextFiber; + } +} + +function prepareToReadContext(workInProgress, renderExpirationTime) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastContextWithAllBitsObserved = null; + + var currentDependencies = workInProgress.contextDependencies; + if (currentDependencies !== null && currentDependencies.expirationTime >= renderExpirationTime) { + // Context list has a pending update. Mark that this fiber performed work. + markWorkInProgressReceivedUpdate(); + } + + // Reset the work-in-progress list + workInProgress.contextDependencies = null; +} + +function readContext(context, observedBits) { + if (lastContextWithAllBitsObserved === context) { + // Nothing to do. We already observe everything in this context. + } else if (observedBits === false || observedBits === 0) { + // Do not observe any updates. + } else { + var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. + if (typeof observedBits !== 'number' || observedBits === maxSigned31BitInt) { + // Observe all updates. + lastContextWithAllBitsObserved = context; + resolvedObservedBits = maxSigned31BitInt; + } else { + resolvedObservedBits = observedBits; + } + + var contextItem = { + context: context, + observedBits: resolvedObservedBits, + next: null + }; + + if (lastContextDependency === null) { + !(currentlyRenderingFiber !== null) ? reactProdInvariant('308') : void 0; + + // This is the first dependency for this component. Create a new list. + lastContextDependency = contextItem; + currentlyRenderingFiber.contextDependencies = { + first: contextItem, + expirationTime: NoWork + }; + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; + } + } + return isPrimaryRenderer ? context._currentValue : context._currentValue2; +} + +// UpdateQueue is a linked list of prioritized updates. +// +// Like fibers, update queues come in pairs: a current queue, which represents +// the visible state of the screen, and a work-in-progress queue, which can be +// mutated and processed asynchronously before it is committed — a form of +// double buffering. If a work-in-progress render is discarded before finishing, +// we create a new work-in-progress by cloning the current queue. +// +// Both queues share a persistent, singly-linked list structure. To schedule an +// update, we append it to the end of both queues. Each queue maintains a +// pointer to first update in the persistent list that hasn't been processed. +// The work-in-progress pointer always has a position equal to or greater than +// the current queue, since we always work on that one. The current queue's +// pointer is only updated during the commit phase, when we swap in the +// work-in-progress. +// +// For example: +// +// Current pointer: A - B - C - D - E - F +// Work-in-progress pointer: D - E - F +// ^ +// The work-in-progress queue has +// processed more updates than current. +// +// The reason we append to both queues is because otherwise we might drop +// updates without ever processing them. For example, if we only add updates to +// the work-in-progress queue, some updates could be lost whenever a work-in +// -progress render restarts by cloning from current. Similarly, if we only add +// updates to the current queue, the updates will be lost whenever an already +// in-progress queue commits and swaps with the current queue. However, by +// adding to both queues, we guarantee that the update will be part of the next +// work-in-progress. (And because the work-in-progress queue becomes the +// current queue once it commits, there's no danger of applying the same +// update twice.) +// +// Prioritization +// -------------- +// +// Updates are not sorted by priority, but by insertion; new updates are always +// appended to the end of the list. +// +// The priority is still important, though. When processing the update queue +// during the render phase, only the updates with sufficient priority are +// included in the result. If we skip an update because it has insufficient +// priority, it remains in the queue to be processed later, during a lower +// priority render. Crucially, all updates subsequent to a skipped update also +// remain in the queue *regardless of their priority*. That means high priority +// updates are sometimes processed twice, at two separate priorities. We also +// keep track of a base state, that represents the state before the first +// update in the queue is applied. +// +// For example: +// +// Given a base state of '', and the following queue of updates +// +// A1 - B2 - C1 - D2 +// +// where the number indicates the priority, and the update is applied to the +// previous state by appending a letter, React will process these updates as +// two separate renders, one per distinct priority level: +// +// First render, at priority 1: +// Base state: '' +// Updates: [A1, C1] +// Result state: 'AC' +// +// Second render, at priority 2: +// Base state: 'A' <- The base state does not include C1, +// because B2 was skipped. +// Updates: [B2, C1, D2] <- C1 was rebased on top of B2 +// Result state: 'ABCD' +// +// Because we process updates in insertion order, and rebase high priority +// updates when preceding updates are skipped, the final result is deterministic +// regardless of priority. Intermediate state may vary according to system +// resources, but the final state is always the same. + +var UpdateState = 0; +var ReplaceState = 1; +var ForceUpdate = 2; +var CaptureUpdate = 3; + +// Global state that is reset at the beginning of calling `processUpdateQueue`. +// It should only be read right after calling `processUpdateQueue`, via +// `checkHasForceUpdateAfterProcessing`. +var hasForceUpdate = false; + + +function createUpdateQueue(baseState) { + var queue = { + baseState: baseState, + firstUpdate: null, + lastUpdate: null, + firstCapturedUpdate: null, + lastCapturedUpdate: null, + firstEffect: null, + lastEffect: null, + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function cloneUpdateQueue(currentQueue) { + var queue = { + baseState: currentQueue.baseState, + firstUpdate: currentQueue.firstUpdate, + lastUpdate: currentQueue.lastUpdate, + + // TODO: With resuming, if we bail out and resuse the child tree, we should + // keep these effects. + firstCapturedUpdate: null, + lastCapturedUpdate: null, + + firstEffect: null, + lastEffect: null, + + firstCapturedEffect: null, + lastCapturedEffect: null + }; + return queue; +} + +function createUpdate(expirationTime) { + return { + expirationTime: expirationTime, + + tag: UpdateState, + payload: null, + callback: null, + + next: null, + nextEffect: null + }; +} + +function appendUpdateToQueue(queue, update) { + // Append the update to the end of the list. + if (queue.lastUpdate === null) { + // Queue is empty + queue.firstUpdate = queue.lastUpdate = update; + } else { + queue.lastUpdate.next = update; + queue.lastUpdate = update; + } +} + +function enqueueUpdate(fiber, update) { + // Update queues are created lazily. + var alternate = fiber.alternate; + var queue1 = void 0; + var queue2 = void 0; + if (alternate === null) { + // There's only one fiber. + queue1 = fiber.updateQueue; + queue2 = null; + if (queue1 === null) { + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + } + } else { + // There are two owners. + queue1 = fiber.updateQueue; + queue2 = alternate.updateQueue; + if (queue1 === null) { + if (queue2 === null) { + // Neither fiber has an update queue. Create new ones. + queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); + queue2 = alternate.updateQueue = createUpdateQueue(alternate.memoizedState); + } else { + // Only one fiber has an update queue. Clone to create a new one. + queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); + } + } else { + if (queue2 === null) { + // Only one fiber has an update queue. Clone to create a new one. + queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); + } else { + // Both owners have an update queue. + } + } + } + if (queue2 === null || queue1 === queue2) { + // There's only a single queue. + appendUpdateToQueue(queue1, update); + } else { + // There are two queues. We need to append the update to both queues, + // while accounting for the persistent structure of the list — we don't + // want the same update to be added multiple times. + if (queue1.lastUpdate === null || queue2.lastUpdate === null) { + // One of the queues is not empty. We must add the update to both queues. + appendUpdateToQueue(queue1, update); + appendUpdateToQueue(queue2, update); + } else { + // Both queues are non-empty. The last update is the same in both lists, + // because of structural sharing. So, only append to one of the lists. + appendUpdateToQueue(queue1, update); + // But we still need to update the `lastUpdate` pointer of queue2. + queue2.lastUpdate = update; + } + } + + +} + +function enqueueCapturedUpdate(workInProgress, update) { + // Captured updates go into a separate list, and only on the work-in- + // progress queue. + var workInProgressQueue = workInProgress.updateQueue; + if (workInProgressQueue === null) { + workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(workInProgress.memoizedState); + } else { + // TODO: I put this here rather than createWorkInProgress so that we don't + // clone the queue unnecessarily. There's probably a better way to + // structure this. + workInProgressQueue = ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); + } + + // Append the update to the end of the list. + if (workInProgressQueue.lastCapturedUpdate === null) { + // This is the first render phase update + workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; + } else { + workInProgressQueue.lastCapturedUpdate.next = update; + workInProgressQueue.lastCapturedUpdate = update; + } +} + +function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { + var current = workInProgress.alternate; + if (current !== null) { + // If the work-in-progress queue is equal to the current queue, + // we need to clone it first. + if (queue === current.updateQueue) { + queue = workInProgress.updateQueue = cloneUpdateQueue(queue); + } + } + return queue; +} + +function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { + switch (update.tag) { + case ReplaceState: + { + var _payload = update.payload; + if (typeof _payload === 'function') { + // Updater function + var nextState = _payload.call(instance, prevState, nextProps); + return nextState; + } + // State object + return _payload; + } + case CaptureUpdate: + { + workInProgress.effectTag = workInProgress.effectTag & ~ShouldCapture | DidCapture; + } + // Intentional fallthrough + case UpdateState: + { + var _payload2 = update.payload; + var partialState = void 0; + if (typeof _payload2 === 'function') { + // Updater function + partialState = _payload2.call(instance, prevState, nextProps); + + } else { + // Partial state object + partialState = _payload2; + } + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } + // Merge the partial state and the previous state. + return _assign({}, prevState, partialState); + } + case ForceUpdate: + { + hasForceUpdate = true; + return prevState; + } + } + return prevState; +} + +function processUpdateQueue(workInProgress, queue, props, instance, renderExpirationTime) { + hasForceUpdate = false; + + queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); + + var newBaseState = queue.baseState; + var newFirstUpdate = null; + var newExpirationTime = NoWork; + + // Iterate through the list of updates to compute the result. + var update = queue.firstUpdate; + var resultState = newBaseState; + while (update !== null) { + var updateExpirationTime = update.expirationTime; + if (updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstUpdate === null) { + // This is the first skipped update. It will be the first update in + // the new list. + newFirstUpdate = update; + // Since this is the first update that was skipped, the current result + // is the new base state. + newBaseState = resultState; + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < updateExpirationTime) { + newExpirationTime = updateExpirationTime; + } + } else { + // This update does have sufficient priority. Process it and compute + // a new result. + resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); + var _callback = update.callback; + if (_callback !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastEffect === null) { + queue.firstEffect = queue.lastEffect = update; + } else { + queue.lastEffect.nextEffect = update; + queue.lastEffect = update; + } + } + } + // Continue to the next update. + update = update.next; + } + + // Separately, iterate though the list of captured updates. + var newFirstCapturedUpdate = null; + update = queue.firstCapturedUpdate; + while (update !== null) { + var _updateExpirationTime = update.expirationTime; + if (_updateExpirationTime < renderExpirationTime) { + // This update does not have sufficient priority. Skip it. + if (newFirstCapturedUpdate === null) { + // This is the first skipped captured update. It will be the first + // update in the new list. + newFirstCapturedUpdate = update; + // If this is the first update that was skipped, the current result is + // the new base state. + if (newFirstUpdate === null) { + newBaseState = resultState; + } + } + // Since this update will remain in the list, update the remaining + // expiration time. + if (newExpirationTime < _updateExpirationTime) { + newExpirationTime = _updateExpirationTime; + } + } else { + // This update does have sufficient priority. Process it and compute + // a new result. + resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); + var _callback2 = update.callback; + if (_callback2 !== null) { + workInProgress.effectTag |= Callback; + // Set this to null, in case it was mutated during an aborted render. + update.nextEffect = null; + if (queue.lastCapturedEffect === null) { + queue.firstCapturedEffect = queue.lastCapturedEffect = update; + } else { + queue.lastCapturedEffect.nextEffect = update; + queue.lastCapturedEffect = update; + } + } + } + update = update.next; + } + + if (newFirstUpdate === null) { + queue.lastUpdate = null; + } + if (newFirstCapturedUpdate === null) { + queue.lastCapturedUpdate = null; + } else { + workInProgress.effectTag |= Callback; + } + if (newFirstUpdate === null && newFirstCapturedUpdate === null) { + // We processed every update, without skipping. That means the new base + // state is the same as the result state. + newBaseState = resultState; + } + + queue.baseState = newBaseState; + queue.firstUpdate = newFirstUpdate; + queue.firstCapturedUpdate = newFirstCapturedUpdate; + + // Set the remaining expiration time to be whatever is remaining in the queue. + // This should be fine because the only two other things that contribute to + // expiration time are props and context. We're already in the middle of the + // begin phase by the time we start processing the queue, so we've already + // dealt with the props. Context in components that specify + // shouldComponentUpdate is tricky; but we'll have to account for + // that regardless. + workInProgress.expirationTime = newExpirationTime; + workInProgress.memoizedState = resultState; + + +} + +function callCallback(callback, context) { + !(typeof callback === 'function') ? reactProdInvariant('191', callback) : void 0; + callback.call(context); +} + +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} + +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} + +function commitUpdateQueue(finishedWork, finishedQueue, instance, renderExpirationTime) { + // If the finished render included captured updates, and there are still + // lower priority updates left over, we need to keep the captured updates + // in the queue so that they are rebased and not dropped once we process the + // queue again at the lower priority. + if (finishedQueue.firstCapturedUpdate !== null) { + // Join the captured update list to the end of the normal list. + if (finishedQueue.lastUpdate !== null) { + finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; + finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; + } + // Clear the list of captured updates. + finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; + } + + // Commit the effects + commitUpdateEffects(finishedQueue.firstEffect, instance); + finishedQueue.firstEffect = finishedQueue.lastEffect = null; + + commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); + finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; +} + +function commitUpdateEffects(effect, instance) { + while (effect !== null) { + var _callback3 = effect.callback; + if (_callback3 !== null) { + effect.callback = null; + callCallback(_callback3, instance); + } + effect = effect.nextEffect; + } +} + +function createCapturedValue(value, source) { + // If the value is an error, call this function immediately after it is thrown + // so the stack is accurate. + return { + value: value, + source: source, + stack: getStackByFiberInDevAndProd(source) + }; +} + +function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.effectTag |= Update; +} + +function markRef$1(workInProgress) { + workInProgress.effectTag |= Ref; +} + +var appendAllChildren = void 0; +var updateHostContainer = void 0; +var updateHostComponent$1 = void 0; +var updateHostText$1 = void 0; +if (supportsMutation) { + // Mutation mode + + appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + if (node.tag === HostComponent || node.tag === HostText) { + appendInitialChild(parent, node.stateNode); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + updateHostContainer = function (workInProgress) { + // Noop + }; + updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { + // If we have an alternate, that means this is an update and we need to + // schedule a side-effect to do the updates. + var oldProps = current.memoizedProps; + if (oldProps === newProps) { + // In mutation mode, this is sufficient for a bailout because + // we won't touch this node even if children changed. + return; + } + + // If we get updated because one of our children updated, we don't + // have newProps so we'll have to reuse them. + // TODO: Split the update API as separate for the props vs. children. + // Even better would be if children weren't special cased at all tho. + var instance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + // TODO: Experiencing an error where oldProps is null. Suggests a host + // component is hitting the resume path. Figure out why. Possibly + // related to `hidden`. + var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); + // TODO: Type this specific to this type of component. + workInProgress.updateQueue = updatePayload; + // If the update payload indicates that there is a change or if there + // is a new ref we mark this as an update. All the work is done in commitWork. + if (updatePayload) { + markUpdate(workInProgress); + } + }; + updateHostText$1 = function (current, workInProgress, oldText, newText) { + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); + } + }; +} else if (supportsPersistence) { + // Persistent host tree mode + + appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle) { + var props = node.memoizedProps; + var type = node.type; + if (isHidden) { + // This child is inside a timed out tree. Hide it. + instance = cloneHiddenInstance(instance, type, props, node); + } else { + // This child was previously inside a timed out tree. If it was not + // updated during this render, it may need to be unhidden. Clone + // again to be sure. + instance = cloneUnhiddenInstance(instance, type, props, node); + } + node.stateNode = instance; + } + appendInitialChild(parent, instance); + } else if (node.tag === HostText) { + var _instance = node.stateNode; + if (needsVisibilityToggle) { + var text = node.memoizedProps; + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + if (isHidden) { + _instance = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); + } else { + _instance = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); + } + node.stateNode = _instance; + } + appendInitialChild(parent, _instance); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + var current = node.alternate; + if (current !== null) { + var oldState = current.memoizedState; + var newState = node.memoizedState; + var oldIsHidden = oldState !== null; + var newIsHidden = newState !== null; + if (oldIsHidden !== newIsHidden) { + // The placeholder either just timed out or switched back to the normal + // children after having previously timed out. Toggle the visibility of + // the direct host children. + var primaryChildParent = newIsHidden ? node.child : node; + if (primaryChildParent !== null) { + appendAllChildren(parent, primaryChildParent, true, newIsHidden); + } + // eslint-disable-next-line no-labels + break branches; + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + + // An unfortunate fork of appendAllChildren because we have two different parent types. + var appendAllChildrenToContainer = function (containerChildSet, workInProgress, needsVisibilityToggle, isHidden) { + // We only have the top Fiber that was created but we need recurse down its + // children to find all the terminal nodes. + var node = workInProgress.child; + while (node !== null) { + // eslint-disable-next-line no-labels + branches: if (node.tag === HostComponent) { + var instance = node.stateNode; + if (needsVisibilityToggle) { + var props = node.memoizedProps; + var type = node.type; + if (isHidden) { + // This child is inside a timed out tree. Hide it. + instance = cloneHiddenInstance(instance, type, props, node); + } else { + // This child was previously inside a timed out tree. If it was not + // updated during this render, it may need to be unhidden. Clone + // again to be sure. + instance = cloneUnhiddenInstance(instance, type, props, node); + } + node.stateNode = instance; + } + appendChildToContainerChildSet(containerChildSet, instance); + } else if (node.tag === HostText) { + var _instance2 = node.stateNode; + if (needsVisibilityToggle) { + var text = node.memoizedProps; + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + if (isHidden) { + _instance2 = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); + } else { + _instance2 = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); + } + node.stateNode = _instance2; + } + appendChildToContainerChildSet(containerChildSet, _instance2); + } else if (node.tag === HostPortal) { + // If we have a portal child, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.tag === SuspenseComponent) { + var current = node.alternate; + if (current !== null) { + var oldState = current.memoizedState; + var newState = node.memoizedState; + var oldIsHidden = oldState !== null; + var newIsHidden = newState !== null; + if (oldIsHidden !== newIsHidden) { + // The placeholder either just timed out or switched back to the normal + // children after having previously timed out. Toggle the visibility of + // the direct host children. + var primaryChildParent = newIsHidden ? node.child : node; + if (primaryChildParent !== null) { + appendAllChildrenToContainer(containerChildSet, primaryChildParent, true, newIsHidden); + } + // eslint-disable-next-line no-labels + break branches; + } + } + if (node.child !== null) { + // Continue traversing like normal + node.child.return = node; + node = node.child; + continue; + } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + // $FlowFixMe This is correct but Flow is confused by the labeled break. + node = node; + if (node === workInProgress) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === workInProgress) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + }; + updateHostContainer = function (workInProgress) { + var portalOrRoot = workInProgress.stateNode; + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged) { + // No changes, just reuse the existing instance. + } else { + var container = portalOrRoot.containerInfo; + var newChildSet = createContainerChildSet(container); + // If children might have changed, we have to add them all to the set. + appendAllChildrenToContainer(newChildSet, workInProgress, false, false); + portalOrRoot.pendingChildren = newChildSet; + // Schedule an update on the container to swap out the container. + markUpdate(workInProgress); + finalizeContainerChildren(container, newChildSet); + } + }; + updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { + var currentInstance = current.stateNode; + var oldProps = current.memoizedProps; + // If there are no effects associated with this node, then none of our children had any updates. + // This guarantees that we can reuse all of them. + var childrenUnchanged = workInProgress.firstEffect === null; + if (childrenUnchanged && oldProps === newProps) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var recyclableInstance = workInProgress.stateNode; + var currentHostContext = getHostContext(); + var updatePayload = null; + if (oldProps !== newProps) { + updatePayload = prepareUpdate(recyclableInstance, type, oldProps, newProps, rootContainerInstance, currentHostContext); + } + if (childrenUnchanged && updatePayload === null) { + // No changes, just reuse the existing instance. + // Note that this might release a previous clone. + workInProgress.stateNode = currentInstance; + return; + } + var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance); + if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance, currentHostContext)) { + markUpdate(workInProgress); + } + workInProgress.stateNode = newInstance; + if (childrenUnchanged) { + // If there are no other effects in this tree, we need to flag this node as having one. + // Even though we're not going to use it for anything. + // Otherwise parents won't know that there are new children to propagate upwards. + markUpdate(workInProgress); + } else { + // If children might have changed, we have to add them all to the set. + appendAllChildren(newInstance, workInProgress, false, false); + } + }; + updateHostText$1 = function (current, workInProgress, oldText, newText) { + if (oldText !== newText) { + // If the text content differs, we'll create a new text instance for it. + var rootContainerInstance = getRootHostContainer(); + var currentHostContext = getHostContext(); + workInProgress.stateNode = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress); + // We'll have to mark it as having an effect, even though we won't use the effect for anything. + // This lets the parents know that at least one of their children has changed. + markUpdate(workInProgress); + } + }; +} else { + // No host operations + updateHostContainer = function (workInProgress) { + // Noop + }; + updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { + // Noop + }; + updateHostText$1 = function (current, workInProgress, oldText, newText) { + // Noop + }; +} + +function completeWork(current, workInProgress, renderExpirationTime) { + var newProps = workInProgress.pendingProps; + + switch (workInProgress.tag) { + case IndeterminateComponent: + break; + case LazyComponent: + break; + case SimpleMemoComponent: + case FunctionComponent: + break; + case ClassComponent: + { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + break; + } + case HostRoot: + { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var fiberRoot = workInProgress.stateNode; + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } + if (current === null || current.child === null) { + // If we hydrated, pop so that we can delete any remaining children + // that weren't hydrated. + popHydrationState(workInProgress); + // This resets the hacky state to fix isMounted before committing. + // TODO: Delete this when we delete isMounted and findDOMNode. + workInProgress.effectTag &= ~Placement; + } + updateHostContainer(workInProgress); + break; + } + case HostComponent: + { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent$1(current, workInProgress, type, newProps, rootContainerInstance); + + if (current.ref !== workInProgress.ref) { + markRef$1(workInProgress); + } + } else { + if (!newProps) { + !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; + // This can happen when we abort work. + break; + } + + var currentHostContext = getHostContext(); + // TODO: Move createInstance to beginWork and keep it on a context + // "stack" as the parent. Then append children as we go in beginWork + // or completeWork depending on we want to add then top->down or + // bottom->up. Top->down is faster in IE11. + var wasHydrated = popHydrationState(workInProgress); + if (wasHydrated) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, currentHostContext)) { + // If changes to the hydrated node needs to be applied at the + // commit-phase we mark this as such. + markUpdate(workInProgress); + } + } else { + var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress); + + appendAllChildren(instance, workInProgress, false, false); + + // Certain renderers require commit-time effects for initial mount. + // (eg DOM renderer supports auto-focus for certain elements). + // Make sure such renderers get scheduled for later work. + if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance, currentHostContext)) { + markUpdate(workInProgress); + } + workInProgress.stateNode = instance; + } + + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef$1(workInProgress); + } + } + break; + } + case HostText: + { + var newText = newProps; + if (current && workInProgress.stateNode != null) { + var oldText = current.memoizedProps; + // If we have an alternate, that means this is an update and we need + // to schedule a side-effect to do the updates. + updateHostText$1(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== 'string') { + !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; + // This can happen when we abort work. + } + var _rootContainerInstance = getRootHostContainer(); + var _currentHostContext = getHostContext(); + var _wasHydrated = popHydrationState(workInProgress); + if (_wasHydrated) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext, workInProgress); + } + } + break; + } + case ForwardRef: + break; + case SuspenseComponent: + { + var nextState = workInProgress.memoizedState; + if ((workInProgress.effectTag & DidCapture) !== NoEffect) { + // Something suspended. Re-render with the fallback children. + workInProgress.expirationTime = renderExpirationTime; + // Do not reset the effect list. + return workInProgress; + } + + var nextDidTimeout = nextState !== null; + var prevDidTimeout = current !== null && current.memoizedState !== null; + + if (current !== null && !nextDidTimeout && prevDidTimeout) { + // We just switched from the fallback to the normal children. Delete + // the fallback. + // TODO: Would it be better to store the fallback fragment on + var currentFallbackChild = current.child.sibling; + if (currentFallbackChild !== null) { + // Deletions go at the beginning of the return fiber's effect list + var first = workInProgress.firstEffect; + if (first !== null) { + workInProgress.firstEffect = currentFallbackChild; + currentFallbackChild.nextEffect = first; + } else { + workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; + currentFallbackChild.nextEffect = null; + } + currentFallbackChild.effectTag = Deletion; + } + } + + if (nextDidTimeout || prevDidTimeout) { + // If the children are hidden, or if they were previous hidden, schedule + // an effect to toggle their visibility. This is also used to attach a + // retry listener to the promise. + workInProgress.effectTag |= Update; + } + break; + } + case Fragment: + break; + case Mode: + break; + case Profiler: + break; + case HostPortal: + popHostContainer(workInProgress); + updateHostContainer(workInProgress); + break; + case ContextProvider: + // Pop provider fiber + popProvider(workInProgress); + break; + case ContextConsumer: + break; + case MemoComponent: + break; + case IncompleteClassComponent: + { + // Same as class component case. I put it down here so that the tags are + // sequential to ensure this switch is compiled to a jump table. + var _Component = workInProgress.type; + if (isContextProvider(_Component)) { + popContext(workInProgress); + } + break; + } + case DehydratedSuspenseComponent: + { + if (enableSuspenseServerRenderer) { + if (current === null) { + var _wasHydrated2 = popHydrationState(workInProgress); + !_wasHydrated2 ? reactProdInvariant('318') : void 0; + skipPastDehydratedSuspenseInstance(workInProgress); + } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { + // This boundary did not suspend so it's now hydrated. + // To handle any future suspense cases, we're going to now upgrade it + // to a Suspense component. We detach it from the existing current fiber. + current.alternate = null; + workInProgress.alternate = null; + workInProgress.tag = SuspenseComponent; + workInProgress.memoizedState = null; + workInProgress.stateNode = null; + } + } + break; + } + default: + reactProdInvariant('156'); + } + + return null; +} + +function shouldCaptureSuspense(workInProgress) { + // In order to capture, the Suspense component must have a fallback prop. + if (workInProgress.memoizedProps.fallback === undefined) { + return false; + } + // If it was the primary children that just suspended, capture and render the + // fallback. Otherwise, don't capture and bubble to the next boundary. + var nextState = workInProgress.memoizedState; + return nextState === null; +} + +// This module is forked in different environments. +// By default, return `true` to log errors to the console. +// Forks can return `false` if this isn't desirable. +function showErrorDialog(capturedError) { + return true; +} + +function logCapturedError(capturedError) { + var logError = showErrorDialog(capturedError); + + // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + if (logError === false) { + return; + } + + var error = capturedError.error; + { + // In production, we print the error directly. + // This will include the message, the JS stack, and anything the browser wants to show. + // We pass the error object instead of custom message so that the browser displays the error natively. + console.error(error); + } +} + +var PossiblyWeakSet$1 = typeof WeakSet === 'function' ? WeakSet : Set; + +function logError(boundary, errorInfo) { + var source = errorInfo.source; + var stack = errorInfo.stack; + if (stack === null && source !== null) { + stack = getStackByFiberInDevAndProd(source); + } + + var capturedError = { + componentName: source !== null ? getComponentName(source.type) : null, + componentStack: stack !== null ? stack : '', + error: errorInfo.value, + errorBoundary: null, + errorBoundaryName: null, + errorBoundaryFound: false, + willRetry: false + }; + + if (boundary !== null && boundary.tag === ClassComponent) { + capturedError.errorBoundary = boundary.stateNode; + capturedError.errorBoundaryName = getComponentName(boundary.type); + capturedError.errorBoundaryFound = true; + capturedError.willRetry = true; + } + + try { + logCapturedError(capturedError); + } catch (e) { + // This method must not throw, or React internal state will get messed up. + // If console.error is overridden, or logCapturedError() shows a dialog that throws, + // we want to report this error outside of the normal stack as a last resort. + // https://github.com/facebook/react/issues/13188 + setTimeout(function () { + throw e; + }); + } +} + +var callComponentWillUnmountWithTimer = function (current$$1, instance) { + startPhaseTimer(current$$1, 'componentWillUnmount'); + instance.props = current$$1.memoizedProps; + instance.state = current$$1.memoizedState; + instance.componentWillUnmount(); + stopPhaseTimer(); +}; + +// Capture errors so they don't interrupt unmounting. +function safelyCallComponentWillUnmount(current$$1, instance) { + { + try { + callComponentWillUnmountWithTimer(current$$1, instance); + } catch (unmountError) { + captureCommitPhaseError(current$$1, unmountError); + } + } +} + +function safelyDetachRef(current$$1) { + var ref = current$$1.ref; + if (ref !== null) { + if (typeof ref === 'function') { + { + try { + ref(null); + } catch (refError) { + captureCommitPhaseError(current$$1, refError); + } + } + } else { + ref.current = null; + } + } +} + +function safelyCallDestroy(current$$1, destroy) { + { + try { + destroy(); + } catch (error) { + captureCommitPhaseError(current$$1, error); + } + } +} + +function commitBeforeMutationLifeCycles(current$$1, finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); + return; + } + case ClassComponent: + { + if (finishedWork.effectTag & Snapshot) { + if (current$$1 !== null) { + var prevProps = current$$1.memoizedProps; + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, 'getSnapshotBeforeUpdate'); + var instance = finishedWork.stateNode; + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + var snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + stopPhaseTimer(); + } + } + return; + } + case HostRoot: + case HostComponent: + case HostText: + case HostPortal: + case IncompleteClassComponent: + // Nothing to do for these component types + return; + default: + { + reactProdInvariant('163'); + } + } +} + +function commitHookEffectList(unmountTag, mountTag, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + if ((effect.tag & unmountTag) !== NoEffect$1) { + // Unmount + var destroy = effect.destroy; + effect.destroy = undefined; + if (destroy !== undefined) { + destroy(); + } + } + if ((effect.tag & mountTag) !== NoEffect$1) { + // Mount + var create = effect.create; + effect.destroy = create(); + + + } + effect = effect.next; + } while (effect !== firstEffect); + } +} + +function commitPassiveHookEffects(finishedWork) { + commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); + commitHookEffectList(NoEffect$1, MountPassive, finishedWork); +} + +function commitLifeCycles(finishedRoot, current$$1, finishedWork, committedExpirationTime) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: + { + commitHookEffectList(UnmountLayout, MountLayout, finishedWork); + break; + } + case ClassComponent: + { + var instance = finishedWork.stateNode; + if (finishedWork.effectTag & Update) { + if (current$$1 === null) { + startPhaseTimer(finishedWork, 'componentDidMount'); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + instance.componentDidMount(); + stopPhaseTimer(); + } else { + var prevProps = finishedWork.elementType === finishedWork.type ? current$$1.memoizedProps : resolveDefaultProps(finishedWork.type, current$$1.memoizedProps); + var prevState = current$$1.memoizedState; + startPhaseTimer(finishedWork, 'componentDidUpdate'); + // We could update instance props and state here, + // but instead we rely on them being set during last render. + // TODO: revisit this when we implement resuming. + instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); + stopPhaseTimer(); + } + } + var updateQueue = finishedWork.updateQueue; + if (updateQueue !== null) { + commitUpdateQueue(finishedWork, updateQueue, instance, committedExpirationTime); + } + return; + } + case HostRoot: + { + var _updateQueue = finishedWork.updateQueue; + if (_updateQueue !== null) { + var _instance = null; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostComponent: + _instance = getPublicInstance(finishedWork.child.stateNode); + break; + case ClassComponent: + _instance = finishedWork.child.stateNode; + break; + } + } + commitUpdateQueue(finishedWork, _updateQueue, _instance, committedExpirationTime); + } + return; + } + case HostComponent: + { + var _instance2 = finishedWork.stateNode; + + // Renderers may schedule work to be done after host components are mounted + // (eg DOM renderer may schedule auto-focus for inputs and form controls). + // These effects should only be committed when components are first mounted, + // aka when there is no current/alternate. + if (current$$1 === null && finishedWork.effectTag & Update) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + + } + + return; + } + case HostText: + { + // We have no life-cycles associated with text. + return; + } + case HostPortal: + { + // We have no life-cycles associated with portals. + return; + } + case Profiler: + { + if (enableProfilerTimer) { + var onRender = finishedWork.memoizedProps.onRender; + + if (enableSchedulerTracing) { + onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime(), finishedRoot.memoizedInteractions); + } else { + onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime()); + } + } + return; + } + case SuspenseComponent: + break; + case IncompleteClassComponent: + break; + default: + { + reactProdInvariant('163'); + } + } +} + +function hideOrUnhideAllChildren(finishedWork, isHidden) { + if (supportsMutation) { + // We only have the top Fiber that was inserted but we need to recurse down its + var node = finishedWork; + while (true) { + if (node.tag === HostComponent) { + var instance = node.stateNode; + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); + } + } else if (node.tag === HostText) { + var _instance3 = node.stateNode; + if (isHidden) { + hideTextInstance(_instance3); + } else { + unhideTextInstance(_instance3, node.memoizedProps); + } + } else if (node.tag === SuspenseComponent && node.memoizedState !== null) { + // Found a nested Suspense component that timed out. Skip over the + var fallbackChildFragment = node.child.sibling; + fallbackChildFragment.return = node; + node = fallbackChildFragment; + continue; + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + } +} + +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse = void 0; + switch (finishedWork.tag) { + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; + default: + instanceToUse = instance; + } + if (typeof ref === 'function') { + ref(instanceToUse); + } else { + ref.current = instanceToUse; + } + } +} + +function commitDetachRef(current$$1) { + var currentRef = current$$1.ref; + if (currentRef !== null) { + if (typeof currentRef === 'function') { + currentRef(null); + } else { + currentRef.current = null; + } + } +} + +// User-originating errors (lifecycles and refs) should not interrupt +// deletion, so don't let them throw. Host-originating errors should +// interrupt deletion, so it's okay +function commitUnmount(current$$1) { + onCommitUnmount(current$$1); + + switch (current$$1.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + var updateQueue = current$$1.updateQueue; + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; + do { + var destroy = effect.destroy; + if (destroy !== undefined) { + safelyCallDestroy(current$$1, destroy); + } + effect = effect.next; + } while (effect !== firstEffect); + } + } + break; + } + case ClassComponent: + { + safelyDetachRef(current$$1); + var instance = current$$1.stateNode; + if (typeof instance.componentWillUnmount === 'function') { + safelyCallComponentWillUnmount(current$$1, instance); + } + return; + } + case HostComponent: + { + safelyDetachRef(current$$1); + return; + } + case HostPortal: + { + // TODO: this is recursive. + // We are also not using this parent because + // the portal will get pushed immediately. + if (supportsMutation) { + unmountHostComponents(current$$1); + } else if (supportsPersistence) { + emptyPortalContainer(current$$1); + } + return; + } + } +} + +function commitNestedUnmounts(root) { + // While we're inside a removed host node we don't want to call + // removeChild on the inner nodes because they're removed by the top + // call anyway. We also want to call componentWillUnmount on all + // composites before this host node is removed from the tree. Therefore + var node = root; + while (true) { + commitUnmount(node); + // Visit children because they may contain more composite or host nodes. + // Skip portals because commitUnmount() currently visits them recursively. + if (node.child !== null && ( + // If we use mutation we drill down into portals using commitUnmount above. + // If we don't use mutation we drill down into portals here instead. + !supportsMutation || node.tag !== HostPortal)) { + node.child.return = node; + node = node.child; + continue; + } + if (node === root) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === root) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function detachFiber(current$$1) { + // Cut off the return pointers to disconnect it from the tree. Ideally, we + // should clear the child pointer of the parent alternate to let this + // get GC:ed but we don't know which for sure which parent is the current + // one so we'll settle for GC:ing the subtree of this child. This child + // itself will be GC:ed when the parent updates the next time. + current$$1.return = null; + current$$1.child = null; + current$$1.memoizedState = null; + current$$1.updateQueue = null; + var alternate = current$$1.alternate; + if (alternate !== null) { + alternate.return = null; + alternate.child = null; + alternate.memoizedState = null; + alternate.updateQueue = null; + } +} + +function emptyPortalContainer(current$$1) { + if (!supportsPersistence) { + return; + } + + var portal = current$$1.stateNode; + var containerInfo = portal.containerInfo; + + var emptyChildSet = createContainerChildSet(containerInfo); + replaceContainerChildren(containerInfo, emptyChildSet); +} + +function commitContainer(finishedWork) { + if (!supportsPersistence) { + return; + } + + switch (finishedWork.tag) { + case ClassComponent: + { + return; + } + case HostComponent: + { + return; + } + case HostText: + { + return; + } + case HostRoot: + case HostPortal: + { + var portalOrRoot = finishedWork.stateNode; + var containerInfo = portalOrRoot.containerInfo, + _pendingChildren = portalOrRoot.pendingChildren; + + replaceContainerChildren(containerInfo, _pendingChildren); + return; + } + default: + { + reactProdInvariant('163'); + } + } +} + +function getHostParentFiber(fiber) { + var parent = fiber.return; + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + parent = parent.return; + } + reactProdInvariant('160'); +} + +function isHostParent(fiber) { + return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; +} + +function getHostSibling(fiber) { + // We're going to search forward into the tree until we find a sibling host + // node. Unfortunately, if multiple insertions are done in a row we have to + // search past them. This leads to exponential search for the next sibling. + var node = fiber; + siblings: while (true) { + // If we didn't find anything, let's try the next sibling. + while (node.sibling === null) { + if (node.return === null || isHostParent(node.return)) { + // If we pop out of the root or hit the parent the fiber we are the + // last sibling. + return null; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + while (node.tag !== HostComponent && node.tag !== HostText && node.tag !== DehydratedSuspenseComponent) { + // If it is not host node and, we might have a host node inside it. + // Try to search down until we find one. + if (node.effectTag & Placement) { + // If we don't have a child, try the siblings instead. + continue siblings; + } + // If we don't have a child, try the siblings instead. + // We also skip portals because they are not part of this host tree. + if (node.child === null || node.tag === HostPortal) { + continue siblings; + } else { + node.child.return = node; + node = node.child; + } + } + // Check if this host node is stable or about to be placed. + if (!(node.effectTag & Placement)) { + // Found it! + return node.stateNode; + } + } +} + +function commitPlacement(finishedWork) { + if (!supportsMutation) { + return; + } + + // Recursively insert all host nodes into the parent. + var parentFiber = getHostParentFiber(finishedWork); + + // Note: these two variables *must* always be updated together. + var parent = void 0; + var isContainer = void 0; + + switch (parentFiber.tag) { + case HostComponent: + parent = parentFiber.stateNode; + isContainer = false; + break; + case HostRoot: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + case HostPortal: + parent = parentFiber.stateNode.containerInfo; + isContainer = true; + break; + default: + reactProdInvariant('161'); + } + if (parentFiber.effectTag & ContentReset) { + // Reset the text content of the parent before doing any insertions + parentFiber.effectTag &= ~ContentReset; + } + + var before = getHostSibling(finishedWork); + // We only have the top Fiber that was inserted but we need to recurse down its + // children to find all the terminal nodes. + var node = finishedWork; + while (true) { + if (node.tag === HostComponent || node.tag === HostText) { + if (before) { + if (isContainer) { + insertInContainerBefore(parent, node.stateNode, before); + } else { + insertBefore(parent, node.stateNode, before); + } + } else { + if (isContainer) { + appendChildToContainer(parent, node.stateNode); + } else { + appendChild(parent, node.stateNode); + } + } + } else if (node.tag === HostPortal) { + // If the insertion itself is a portal, then we don't want to traverse + // down its children. Instead, we'll get insertions from each child in + // the portal directly. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + if (node === finishedWork) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function unmountHostComponents(current$$1) { + // We only have the top Fiber that was deleted but we need to recurse down its + var node = current$$1; + + // Each iteration, currentParent is populated with node's host parent if not + // currentParentIsValid. + var currentParentIsValid = false; + + // Note: these two variables *must* always be updated together. + var currentParent = void 0; + var currentParentIsContainer = void 0; + + while (true) { + if (!currentParentIsValid) { + var parent = node.return; + findParent: while (true) { + !(parent !== null) ? reactProdInvariant('160') : void 0; + switch (parent.tag) { + case HostComponent: + currentParent = parent.stateNode; + currentParentIsContainer = false; + break findParent; + case HostRoot: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + case HostPortal: + currentParent = parent.stateNode.containerInfo; + currentParentIsContainer = true; + break findParent; + } + parent = parent.return; + } + currentParentIsValid = true; + } + + if (node.tag === HostComponent || node.tag === HostText) { + commitNestedUnmounts(node); + // After all the children have unmounted, it is now safe to remove the + // node from the tree. + if (currentParentIsContainer) { + removeChildFromContainer(currentParent, node.stateNode); + } else { + removeChild(currentParent, node.stateNode); + } + // Don't visit children because we already visited them. + } else if (enableSuspenseServerRenderer && node.tag === DehydratedSuspenseComponent) { + // Delete the dehydrated suspense boundary and all of its content. + if (currentParentIsContainer) { + clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); + } else { + clearSuspenseBoundary(currentParent, node.stateNode); + } + } else if (node.tag === HostPortal) { + if (node.child !== null) { + // When we go into a portal, it becomes the parent to remove from. + // We will reassign it back when we pop the portal on the way up. + currentParent = node.stateNode.containerInfo; + currentParentIsContainer = true; + // Visit children because portals might contain host components. + node.child.return = node; + node = node.child; + continue; + } + } else { + commitUnmount(node); + // Visit children because we may find more host components below. + if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + } + if (node === current$$1) { + return; + } + while (node.sibling === null) { + if (node.return === null || node.return === current$$1) { + return; + } + node = node.return; + if (node.tag === HostPortal) { + // When we go out of the portal, we need to restore the parent. + // Since we don't keep a stack of them, we will search for it. + currentParentIsValid = false; + } + } + node.sibling.return = node.return; + node = node.sibling; + } +} + +function commitDeletion(current$$1) { + if (supportsMutation) { + // Recursively delete all host nodes from the parent. + // Detach refs and call componentWillUnmount() on the whole subtree. + unmountHostComponents(current$$1); + } else { + // Detach refs and call componentWillUnmount() on the whole subtree. + commitNestedUnmounts(current$$1); + } + detachFiber(current$$1); +} + +function commitWork(current$$1, finishedWork) { + if (!supportsMutation) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + } + + commitContainer(finishedWork); + return; + } + + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: + { + // Note: We currently never use MountMutation, but useLayout uses + // UnmountMutation. + commitHookEffectList(UnmountMutation, MountMutation, finishedWork); + return; + } + case ClassComponent: + { + return; + } + case HostComponent: + { + var instance = finishedWork.stateNode; + if (instance != null) { + // Commit the work prepared earlier. + var newProps = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldProps = current$$1 !== null ? current$$1.memoizedProps : newProps; + var type = finishedWork.type; + // TODO: Type the updateQueue to be specific to host components. + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + if (updatePayload !== null) { + commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork); + } + } + return; + } + case HostText: + { + !(finishedWork.stateNode !== null) ? reactProdInvariant('162') : void 0; + var textInstance = finishedWork.stateNode; + var newText = finishedWork.memoizedProps; + // For hydration we reuse the update path but we treat the oldProps + // as the newProps. The updatePayload will contain the real change in + // this case. + var oldText = current$$1 !== null ? current$$1.memoizedProps : newText; + commitTextUpdate(textInstance, oldText, newText); + return; + } + case HostRoot: + { + return; + } + case Profiler: + { + return; + } + case SuspenseComponent: + { + var newState = finishedWork.memoizedState; + + var newDidTimeout = void 0; + var primaryChildParent = finishedWork; + if (newState === null) { + newDidTimeout = false; + } else { + newDidTimeout = true; + primaryChildParent = finishedWork.child; + if (newState.timedOutAt === NoWork) { + // If the children had not already timed out, record the time. + // This is used to compute the elapsed time during subsequent + // attempts to render the children. + newState.timedOutAt = requestCurrentTime(); + } + } + + if (primaryChildParent !== null) { + hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); + } + + // If this boundary just timed out, then it will have a set of thenables. + // For each thenable, attach a listener so that when it resolves, React + // attempts to re-render the boundary in the primary (pre-timeout) state. + var thenables = finishedWork.updateQueue; + if (thenables !== null) { + finishedWork.updateQueue = null; + var retryCache = finishedWork.stateNode; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); + } + thenables.forEach(function (thenable) { + // Memoize using the boundary fiber to prevent redundant listeners. + var retry = retryTimedOutBoundary.bind(null, finishedWork, thenable); + if (enableSchedulerTracing) { + retry = unstable_wrap(retry); + } + if (!retryCache.has(thenable)) { + retryCache.add(thenable); + thenable.then(retry, retry); + } + }); + } + + return; + } + case IncompleteClassComponent: + { + return; + } + default: + { + reactProdInvariant('163'); + } + } +} + +function commitResetTextContent(current$$1) { + if (!supportsMutation) { + return; + } + resetTextContent(current$$1.stateNode); +} + +var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; +var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; + +function createRootErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + // Unmount the root by rendering null. + update.tag = CaptureUpdate; + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: null }; + var error = errorInfo.value; + update.callback = function () { + onUncaughtError(error); + logError(fiber, errorInfo); + }; + return update; +} + +function createClassErrorUpdate(fiber, errorInfo, expirationTime) { + var update = createUpdate(expirationTime); + update.tag = CaptureUpdate; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; + if (typeof getDerivedStateFromError === 'function') { + var error = errorInfo.value; + update.payload = function () { + return getDerivedStateFromError(error); + }; + } + + var inst = fiber.stateNode; + if (inst !== null && typeof inst.componentDidCatch === 'function') { + update.callback = function callback() { + if (typeof getDerivedStateFromError !== 'function') { + // To preserve the preexisting retry behavior of error boundaries, + // we keep track of which ones already failed during this batch. + // This gets reset before we yield back to the browser. + // TODO: Warn in strict mode if getDerivedStateFromError is + // not defined. + markLegacyErrorBoundaryAsFailed(this); + } + var error = errorInfo.value; + var stack = errorInfo.stack; + logError(fiber, errorInfo); + this.componentDidCatch(error, { + componentStack: stack !== null ? stack : '' + }); + + }; + } + return update; +} + +function attachPingListener(root, renderExpirationTime, thenable) { + // Attach a listener to the promise to "ping" the root and retry. But + // only if one does not already exist for the current render expiration + // time (which acts like a "thread ID" here). + var pingCache = root.pingCache; + var threadIDs = void 0; + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } else { + threadIDs = pingCache.get(thenable); + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(thenable, threadIDs); + } + } + if (!threadIDs.has(renderExpirationTime)) { + // Memoize using the thread ID to prevent redundant listeners. + threadIDs.add(renderExpirationTime); + var ping = pingSuspendedRoot.bind(null, root, thenable, renderExpirationTime); + if (enableSchedulerTracing) { + ping = unstable_wrap(ping); + } + thenable.then(ping, ping); + } +} + +function throwException(root, returnFiber, sourceFiber, value, renderExpirationTime) { + // The source fiber did not complete. + sourceFiber.effectTag |= Incomplete; + // Its effect list is no longer valid. + sourceFiber.firstEffect = sourceFiber.lastEffect = null; + + if (value !== null && typeof value === 'object' && typeof value.then === 'function') { + // This is a thenable. + var thenable = value; + + // Find the earliest timeout threshold of all the placeholders in the + // ancestor path. We could avoid this traversal by storing the thresholds on + // the stack, but we choose not to because we only hit this path if we're + // IO-bound (i.e. if something suspends). Whereas the stack is used even in + // the non-IO- bound case. + var _workInProgress = returnFiber; + var earliestTimeoutMs = -1; + var startTimeMs = -1; + do { + if (_workInProgress.tag === SuspenseComponent) { + var current$$1 = _workInProgress.alternate; + if (current$$1 !== null) { + var currentState = current$$1.memoizedState; + if (currentState !== null) { + // Reached a boundary that already timed out. Do not search + // any further. + var timedOutAt = currentState.timedOutAt; + startTimeMs = expirationTimeToMs(timedOutAt); + // Do not search any further. + break; + } + } + var timeoutPropMs = _workInProgress.pendingProps.maxDuration; + if (typeof timeoutPropMs === 'number') { + if (timeoutPropMs <= 0) { + earliestTimeoutMs = 0; + } else if (earliestTimeoutMs === -1 || timeoutPropMs < earliestTimeoutMs) { + earliestTimeoutMs = timeoutPropMs; + } + } + } + // If there is a DehydratedSuspenseComponent we don't have to do anything because + // if something suspends inside it, we will simply leave that as dehydrated. It + // will never timeout. + _workInProgress = _workInProgress.return; + } while (_workInProgress !== null); + + // Schedule the nearest Suspense to re-render the timed out view. + _workInProgress = returnFiber; + do { + if (_workInProgress.tag === SuspenseComponent && shouldCaptureSuspense(_workInProgress)) { + // Found the nearest boundary. + + // Stash the promise on the boundary fiber. If the boundary times out, we'll + var thenables = _workInProgress.updateQueue; + if (thenables === null) { + var updateQueue = new Set(); + updateQueue.add(thenable); + _workInProgress.updateQueue = updateQueue; + } else { + thenables.add(thenable); + } + + // If the boundary is outside of concurrent mode, we should *not* + // suspend the commit. Pretend as if the suspended component rendered + // null and keep rendering. In the commit phase, we'll schedule a + // subsequent synchronous update to re-render the Suspense. + // + // Note: It doesn't matter whether the component that suspended was + // inside a concurrent mode tree. If the Suspense is outside of it, we + // should *not* suspend the commit. + if ((_workInProgress.mode & ConcurrentMode) === NoEffect) { + _workInProgress.effectTag |= DidCapture; + + // We're going to commit this fiber even though it didn't complete. + // But we shouldn't call any lifecycle methods or callbacks. Remove + // all lifecycle effect tags. + sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); + + if (sourceFiber.tag === ClassComponent) { + var currentSourceFiber = sourceFiber.alternate; + if (currentSourceFiber === null) { + // This is a new mount. Change the tag so it's not mistaken for a + // completed class component. For example, we should not call + // componentWillUnmount if it is deleted. + sourceFiber.tag = IncompleteClassComponent; + } else { + // When we try rendering again, we should not reuse the current fiber, + // since it's known to be in an inconsistent state. Use a force updte to + // prevent a bail out. + var update = createUpdate(Sync); + update.tag = ForceUpdate; + enqueueUpdate(sourceFiber, update); + } + } + + // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. + sourceFiber.expirationTime = Sync; + + // Exit without suspending. + return; + } + + // Confirmed that the boundary is in a concurrent mode tree. Continue + // with the normal suspend path. + + attachPingListener(root, renderExpirationTime, thenable); + + var absoluteTimeoutMs = void 0; + if (earliestTimeoutMs === -1) { + // If no explicit threshold is given, default to an arbitrarily large + // value. The actual size doesn't matter because the threshold for the + // whole tree will be clamped to the expiration time. + absoluteTimeoutMs = maxSigned31BitInt; + } else { + if (startTimeMs === -1) { + // This suspend happened outside of any already timed-out + // placeholders. We don't know exactly when the update was + // scheduled, but we can infer an approximate start time from the + // expiration time. First, find the earliest uncommitted expiration + // time in the tree, including work that is suspended. Then subtract + // the offset used to compute an async update's expiration time. + // This will cause high priority (interactive) work to expire + // earlier than necessary, but we can account for this by adjusting + // for the Just Noticeable Difference. + var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, renderExpirationTime); + var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); + startTimeMs = earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; + } + absoluteTimeoutMs = startTimeMs + earliestTimeoutMs; + } + + // Mark the earliest timeout in the suspended fiber's ancestor path. + // After completing the root, we'll take the largest of all the + // suspended fiber's timeouts and use it to compute a timeout for the + // whole tree. + renderDidSuspend(root, absoluteTimeoutMs, renderExpirationTime); + + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } else if (enableSuspenseServerRenderer && _workInProgress.tag === DehydratedSuspenseComponent) { + attachPingListener(root, renderExpirationTime, thenable); + + // Since we already have a current fiber, we can eagerly add a retry listener. + var retryCache = _workInProgress.memoizedState; + if (retryCache === null) { + retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); + var _current = _workInProgress.alternate; + !_current ? reactProdInvariant('319') : void 0; + _current.memoizedState = retryCache; + } + // Memoize using the boundary fiber to prevent redundant listeners. + if (!retryCache.has(thenable)) { + retryCache.add(thenable); + var retry = retryTimedOutBoundary.bind(null, _workInProgress, thenable); + if (enableSchedulerTracing) { + retry = unstable_wrap(retry); + } + thenable.then(retry, retry); + } + _workInProgress.effectTag |= ShouldCapture; + _workInProgress.expirationTime = renderExpirationTime; + return; + } + // This boundary already captured during this render. Continue to the next + // boundary. + _workInProgress = _workInProgress.return; + } while (_workInProgress !== null); + // No boundary was found. Fallthrough to error mode. + // TODO: Use invariant so the message is stripped in prod? + value = new Error((getComponentName(sourceFiber.type) || 'A React component') + ' suspended while rendering, but no fallback UI was specified.\n' + '\n' + 'Add a <Suspense fallback=...> component higher in the tree to ' + 'provide a loading indicator or placeholder to display.' + getStackByFiberInDevAndProd(sourceFiber)); + } + + // We didn't find a boundary that could handle this type of exception. Start + // over and traverse parent path again, this time treating the exception + // as an error. + renderDidError(); + value = createCapturedValue(value, sourceFiber); + var workInProgress = returnFiber; + do { + switch (workInProgress.tag) { + case HostRoot: + { + var _errorInfo = value; + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + var _update = createRootErrorUpdate(workInProgress, _errorInfo, renderExpirationTime); + enqueueCapturedUpdate(workInProgress, _update); + return; + } + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; + if ((workInProgress.effectTag & DidCapture) === NoEffect && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { + workInProgress.effectTag |= ShouldCapture; + workInProgress.expirationTime = renderExpirationTime; + // Schedule the error boundary to re-render using updated state + var _update2 = createClassErrorUpdate(workInProgress, errorInfo, renderExpirationTime); + enqueueCapturedUpdate(workInProgress, _update2); + return; + } + break; + default: + break; + } + workInProgress = workInProgress.return; + } while (workInProgress !== null); +} + +function unwindWork(workInProgress, renderExpirationTime) { + switch (workInProgress.tag) { + case ClassComponent: + { + var Component = workInProgress.type; + if (isContextProvider(Component)) { + popContext(workInProgress); + } + var effectTag = workInProgress.effectTag; + if (effectTag & ShouldCapture) { + workInProgress.effectTag = effectTag & ~ShouldCapture | DidCapture; + return workInProgress; + } + return null; + } + case HostRoot: + { + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + var _effectTag = workInProgress.effectTag; + !((_effectTag & DidCapture) === NoEffect) ? reactProdInvariant('285') : void 0; + workInProgress.effectTag = _effectTag & ~ShouldCapture | DidCapture; + return workInProgress; + } + case HostComponent: + { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; + } + case SuspenseComponent: + { + var _effectTag2 = workInProgress.effectTag; + if (_effectTag2 & ShouldCapture) { + workInProgress.effectTag = _effectTag2 & ~ShouldCapture | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + return null; + } + case DehydratedSuspenseComponent: + { + if (enableSuspenseServerRenderer) { + // TODO: popHydrationState + var _effectTag3 = workInProgress.effectTag; + if (_effectTag3 & ShouldCapture) { + workInProgress.effectTag = _effectTag3 & ~ShouldCapture | DidCapture; + // Captured a suspense effect. Re-render the boundary. + return workInProgress; + } + } + return null; + } + case HostPortal: + popHostContainer(workInProgress); + return null; + case ContextProvider: + popProvider(workInProgress); + return null; + default: + return null; + } +} + +function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: + { + var childContextTypes = interruptedWork.type.childContextTypes; + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); + } + break; + } + case HostRoot: + { + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + break; + } + case HostComponent: + { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } +} + +var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; +var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; + + +if (enableSchedulerTracing) { + // Provide explicit error message when production+profiling bundle of e.g. react-dom + // is used with production (non-profiling) bundle of scheduler/tracing + !(__interactionsRef != null && __interactionsRef.current != null) ? reactProdInvariant('302') : void 0; +} + +var isWorking = false; + +// The next work in progress fiber that we're currently working on. +var nextUnitOfWork = null; +var nextRoot = null; +// The time at which we're currently rendering work. +var nextRenderExpirationTime = NoWork; +var nextLatestAbsoluteTimeoutMs = -1; +var nextRenderDidError = false; + +// The next fiber with an effect that we're currently committing. +var nextEffect = null; + +var isCommitting$1 = false; +var rootWithPendingPassiveEffects = null; +var passiveEffectCallbackHandle = null; +var passiveEffectCallback = null; + +var legacyErrorBoundariesThatAlreadyFailed = null; + +// Used for performance tracking. +var interruptedBy = null; + +function resetStack() { + if (nextUnitOfWork !== null) { + var interruptedWork = nextUnitOfWork.return; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork.return; + } + } + + nextRoot = null; + nextRenderExpirationTime = NoWork; + nextLatestAbsoluteTimeoutMs = -1; + nextRenderDidError = false; + nextUnitOfWork = null; +} + +function commitAllHostEffects() { + while (nextEffect !== null) { + recordEffect(); + + var effectTag = nextEffect.effectTag; + + if (effectTag & ContentReset) { + commitResetTextContent(nextEffect); + } + + if (effectTag & Ref) { + var current$$1 = nextEffect.alternate; + if (current$$1 !== null) { + commitDetachRef(current$$1); + } + } + + // The following switch statement is only concerned about placement, + // updates, and deletions. To avoid needing to add a case for every + // possible bitmap value, we remove the secondary effects from the + // effect tag and switch on that value. + var primaryEffectTag = effectTag & (Placement | Update | Deletion); + switch (primaryEffectTag) { + case Placement: + { + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is inserted, before + // any life-cycles like componentDidMount gets called. + // TODO: findDOMNode doesn't rely on this any more but isMounted + // does and isMounted is deprecated anyway so we should be able + // to kill this. + nextEffect.effectTag &= ~Placement; + break; + } + case PlacementAndUpdate: + { + // Placement + commitPlacement(nextEffect); + // Clear the "placement" from effect tag so that we know that this is inserted, before + // any life-cycles like componentDidMount gets called. + nextEffect.effectTag &= ~Placement; + + // Update + var _current = nextEffect.alternate; + commitWork(_current, nextEffect); + break; + } + case Update: + { + var _current2 = nextEffect.alternate; + commitWork(_current2, nextEffect); + break; + } + case Deletion: + { + commitDeletion(nextEffect); + break; + } + } + nextEffect = nextEffect.nextEffect; + } + + +} + +function commitBeforeMutationLifecycles() { + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + if (effectTag & Snapshot) { + recordEffect(); + var current$$1 = nextEffect.alternate; + commitBeforeMutationLifeCycles(current$$1, nextEffect); + } + + nextEffect = nextEffect.nextEffect; + } + + +} + +function commitAllLifeCycles(finishedRoot, committedExpirationTime) { + while (nextEffect !== null) { + var effectTag = nextEffect.effectTag; + + if (effectTag & (Update | Callback)) { + recordEffect(); + var current$$1 = nextEffect.alternate; + commitLifeCycles(finishedRoot, current$$1, nextEffect, committedExpirationTime); + } + + if (effectTag & Ref) { + recordEffect(); + commitAttachRef(nextEffect); + } + + if (effectTag & Passive) { + rootWithPendingPassiveEffects = finishedRoot; + } + + nextEffect = nextEffect.nextEffect; + } + +} + +function commitPassiveEffects(root, firstEffect) { + rootWithPendingPassiveEffects = null; + passiveEffectCallbackHandle = null; + passiveEffectCallback = null; + + // Set this to true to prevent re-entrancy + var previousIsRendering = isRendering; + isRendering = true; + + var effect = firstEffect; + do { + if (effect.effectTag & Passive) { + var didError = false; + var error = void 0; + { + try { + commitPassiveHookEffects(effect); + } catch (e) { + didError = true; + error = e; + } + } + if (didError) { + captureCommitPhaseError(effect, error); + } + } + effect = effect.nextEffect; + } while (effect !== null); + isRendering = previousIsRendering; + + // Check if work was scheduled by one of the effects + var rootExpirationTime = root.expirationTime; + if (rootExpirationTime !== NoWork) { + requestWork(root, rootExpirationTime); + } + // Flush any sync work that was scheduled by effects + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } +} + +function isAlreadyFailedLegacyErrorBoundary(instance) { + return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); +} + +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} + +function flushPassiveEffects$1() { + if (passiveEffectCallbackHandle !== null) { + cancelPassiveEffects(passiveEffectCallbackHandle); + } + if (passiveEffectCallback !== null) { + // We call the scheduled callback instead of commitPassiveEffects directly + // to ensure tracing works correctly. + passiveEffectCallback(); + } +} + +function commitRoot(root, finishedWork) { + isWorking = true; + isCommitting$1 = true; + startCommitTimer(); + + !(root.current !== finishedWork) ? reactProdInvariant('177') : void 0; + var committedExpirationTime = root.pendingCommitExpirationTime; + !(committedExpirationTime !== NoWork) ? reactProdInvariant('261') : void 0; + root.pendingCommitExpirationTime = NoWork; + + // Update the pending priority levels to account for the work that we are + // about to commit. This needs to happen before calling the lifecycles, since + // they may schedule additional updates. + var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; + var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; + var earliestRemainingTimeBeforeCommit = childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit ? childExpirationTimeBeforeCommit : updateExpirationTimeBeforeCommit; + markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit); + + var prevInteractions = null; + if (enableSchedulerTracing) { + // Restore any pending interactions at this point, + // So that cascading work triggered during the render phase will be accounted for. + prevInteractions = __interactionsRef.current; + __interactionsRef.current = root.memoizedInteractions; + } + + // Reset this to null before calling lifecycles + ReactCurrentOwner$1.current = null; + + var firstEffect = void 0; + if (finishedWork.effectTag > PerformedWork) { + // A fiber's effect list consists only of its children, not itself. So if + // the root has an effect, we need to add it to the end of the list. The + // resulting list is the set that would belong to the root's parent, if + // it had one; that is, all the effects in the tree including the root. + if (finishedWork.lastEffect !== null) { + finishedWork.lastEffect.nextEffect = finishedWork; + firstEffect = finishedWork.firstEffect; + } else { + firstEffect = finishedWork; + } + } else { + // There is no effect on the root. + firstEffect = finishedWork.firstEffect; + } + + prepareForCommit(root.containerInfo); + + // Invoke instances of getSnapshotBeforeUpdate before mutation. + nextEffect = firstEffect; + startCommitSnapshotEffectsTimer(); + while (nextEffect !== null) { + var didError = false; + var error = void 0; + { + try { + commitBeforeMutationLifecycles(); + } catch (e) { + didError = true; + error = e; + } + } + if (didError) { + !(nextEffect !== null) ? reactProdInvariant('178') : void 0; + captureCommitPhaseError(nextEffect, error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + stopCommitSnapshotEffectsTimer(); + + if (enableProfilerTimer) { + // Mark the current commit time to be shared by all Profilers in this batch. + // This enables them to be grouped later. + recordCommitTime(); + } + + // Commit all the side-effects within a tree. We'll do this in two passes. + // The first pass performs all the host insertions, updates, deletions and + // ref unmounts. + nextEffect = firstEffect; + startCommitHostEffectsTimer(); + while (nextEffect !== null) { + var _didError = false; + var _error = void 0; + { + try { + commitAllHostEffects(); + } catch (e) { + _didError = true; + _error = e; + } + } + if (_didError) { + !(nextEffect !== null) ? reactProdInvariant('178') : void 0; + captureCommitPhaseError(nextEffect, _error); + // Clean-up + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + stopCommitHostEffectsTimer(); + + resetAfterCommit(root.containerInfo); + + // The work-in-progress tree is now the current tree. This must come after + // the first pass of the commit phase, so that the previous tree is still + // current during componentWillUnmount, but before the second pass, so that + // the finished work is current during componentDidMount/Update. + root.current = finishedWork; + + // In the second pass we'll perform all life-cycles and ref callbacks. + // Life-cycles happen as a separate pass so that all placements, updates, + // and deletions in the entire tree have already been invoked. + // This pass also triggers any renderer-specific initial effects. + nextEffect = firstEffect; + startCommitLifeCyclesTimer(); + while (nextEffect !== null) { + var _didError2 = false; + var _error2 = void 0; + { + try { + commitAllLifeCycles(root, committedExpirationTime); + } catch (e) { + _didError2 = true; + _error2 = e; + } + } + if (_didError2) { + !(nextEffect !== null) ? reactProdInvariant('178') : void 0; + captureCommitPhaseError(nextEffect, _error2); + if (nextEffect !== null) { + nextEffect = nextEffect.nextEffect; + } + } + } + + if (firstEffect !== null && rootWithPendingPassiveEffects !== null) { + // This commit included a passive effect. These do not need to fire until + // after the next paint. Schedule an callback to fire them in an async + // event. To ensure serial execution, the callback will be flushed early if + // we enter rootWithPendingPassiveEffects commit phase before then. + var callback = commitPassiveEffects.bind(null, root, firstEffect); + if (enableSchedulerTracing) { + // TODO: Avoid this extra callback by mutating the tracing ref directly, + // like we do at the beginning of commitRoot. I've opted not to do that + // here because that code is still in flux. + callback = unstable_wrap(callback); + } + passiveEffectCallbackHandle = unstable_runWithPriority(unstable_NormalPriority, function () { + return schedulePassiveEffects(callback); + }); + passiveEffectCallback = callback; + } + + isCommitting$1 = false; + isWorking = false; + stopCommitLifeCyclesTimer(); + stopCommitTimer(); + onCommitRoot(finishedWork.stateNode); + var updateExpirationTimeAfterCommit = finishedWork.expirationTime; + var childExpirationTimeAfterCommit = finishedWork.childExpirationTime; + var earliestRemainingTimeAfterCommit = childExpirationTimeAfterCommit > updateExpirationTimeAfterCommit ? childExpirationTimeAfterCommit : updateExpirationTimeAfterCommit; + if (earliestRemainingTimeAfterCommit === NoWork) { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; + } + onCommit(root, earliestRemainingTimeAfterCommit); + + if (enableSchedulerTracing) { + __interactionsRef.current = prevInteractions; + + var subscriber = void 0; + + try { + subscriber = __subscriberRef.current; + if (subscriber !== null && root.memoizedInteractions.size > 0) { + var threadID = computeThreadID(committedExpirationTime, root.interactionThreadID); + subscriber.onWorkStopped(root.memoizedInteractions, threadID); + } + } catch (error) { + // It's not safe for commitRoot() to throw. + // Store the error for now and we'll re-throw in finishRendering(). + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } finally { + // Clear completed interactions from the pending Map. + // Unless the render was suspended or cascading work was scheduled, + // In which case– leave pending interactions until the subsequent render. + var pendingInteractionMap = root.pendingInteractionMap; + pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { + // Only decrement the pending interaction count if we're done. + // If there's still work at the current priority, + // That indicates that we are waiting for suspense data. + if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { + pendingInteractionMap.delete(scheduledExpirationTime); + + scheduledInteractions.forEach(function (interaction) { + interaction.__count--; + + if (subscriber !== null && interaction.__count === 0) { + try { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } catch (error) { + // It's not safe for commitRoot() to throw. + // Store the error for now and we'll re-throw in finishRendering(). + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } + } + }); + } + }); + } + } +} + +function resetChildExpirationTime(workInProgress, renderTime) { + if (renderTime !== Never && workInProgress.childExpirationTime === Never) { + // The children of this component are hidden. Don't bubble their + // expiration times. + return; + } + + var newChildExpirationTime = NoWork; + + // Bubble up the earliest expiration time. + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // We're in profiling mode. + // Let's use this same traversal to update the render durations. + var actualDuration = workInProgress.actualDuration; + var treeBaseDuration = workInProgress.selfBaseDuration; + + // When a fiber is cloned, its actualDuration is reset to 0. + // This value will only be updated if work is done on the fiber (i.e. it doesn't bailout). + // When work is done, it should bubble to the parent's actualDuration. + // If the fiber has not been cloned though, (meaning no work was done), + // Then this value will reflect the amount of time spent working on a previous render. + // In that case it should not bubble. + // We determine whether it was cloned by comparing the child pointer. + var shouldBubbleActualDurations = workInProgress.alternate === null || workInProgress.child !== workInProgress.alternate.child; + + var child = workInProgress.child; + while (child !== null) { + var childUpdateExpirationTime = child.expirationTime; + var childChildExpirationTime = child.childExpirationTime; + if (childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childUpdateExpirationTime; + } + if (childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = childChildExpirationTime; + } + if (shouldBubbleActualDurations) { + actualDuration += child.actualDuration; + } + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; + } + workInProgress.actualDuration = actualDuration; + workInProgress.treeBaseDuration = treeBaseDuration; + } else { + var _child = workInProgress.child; + while (_child !== null) { + var _childUpdateExpirationTime = _child.expirationTime; + var _childChildExpirationTime = _child.childExpirationTime; + if (_childUpdateExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childUpdateExpirationTime; + } + if (_childChildExpirationTime > newChildExpirationTime) { + newChildExpirationTime = _childChildExpirationTime; + } + _child = _child.sibling; + } + } + + workInProgress.childExpirationTime = newChildExpirationTime; +} + +function completeUnitOfWork(workInProgress) { + // Attempt to complete the current unit of work, then move to the + // next sibling. If there are no more siblings, return to the + // parent fiber. + while (true) { + // The current, flushed, state of this fiber is the alternate. + // Ideally nothing should rely on this, but relying on it here + // means that we don't need an additional field on the work in + // progress. + var current$$1 = workInProgress.alternate; + var returnFiber = workInProgress.return; + var siblingFiber = workInProgress.sibling; + + if ((workInProgress.effectTag & Incomplete) === NoEffect) { + nextUnitOfWork = workInProgress; + if (enableProfilerTimer) { + if (workInProgress.mode & ProfileMode) { + startProfilerTimer(workInProgress); + } + nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); + if (workInProgress.mode & ProfileMode) { + // Update render duration assuming we didn't error. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + } + } else { + nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); + } + stopWorkTimer(workInProgress); + resetChildExpirationTime(workInProgress, nextRenderExpirationTime); + if (nextUnitOfWork !== null) { + // Completing this fiber spawned new work. Work on that next. + return nextUnitOfWork; + } + + if (returnFiber !== null && + // Do not append effects to parents if a sibling failed to complete + (returnFiber.effectTag & Incomplete) === NoEffect) { + // Append all the effects of the subtree and this fiber onto the effect + // list of the parent. The completion order of the children affects the + // side-effect order. + if (returnFiber.firstEffect === null) { + returnFiber.firstEffect = workInProgress.firstEffect; + } + if (workInProgress.lastEffect !== null) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; + } + returnFiber.lastEffect = workInProgress.lastEffect; + } + + // If this fiber had side-effects, we append it AFTER the children's + // side-effects. We can perform certain side-effects earlier if + // needed, by doing multiple passes over the effect list. We don't want + // to schedule our own side-effect on our own list because if end up + // reusing children we'll schedule this effect onto itself since we're + // at the end. + var effectTag = workInProgress.effectTag; + // Skip both NoWork and PerformedWork tags when creating the effect list. + // PerformedWork effect is read by React DevTools but shouldn't be committed. + if (effectTag > PerformedWork) { + if (returnFiber.lastEffect !== null) { + returnFiber.lastEffect.nextEffect = workInProgress; + } else { + returnFiber.firstEffect = workInProgress; + } + returnFiber.lastEffect = workInProgress; + } + } + + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } else if (returnFiber !== null) { + // If there's no more work in this returnFiber. Complete the returnFiber. + workInProgress = returnFiber; + continue; + } else { + // We've reached the root. + return null; + } + } else { + if (enableProfilerTimer && workInProgress.mode & ProfileMode) { + // Record the render duration for the fiber that errored. + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); + + // Include the time spent working on failed children before continuing. + var actualDuration = workInProgress.actualDuration; + var child = workInProgress.child; + while (child !== null) { + actualDuration += child.actualDuration; + child = child.sibling; + } + workInProgress.actualDuration = actualDuration; + } + + // This fiber did not complete because something threw. Pop values off + // the stack without entering the complete phase. If this is a boundary, + // capture values if possible. + var next = unwindWork(workInProgress, nextRenderExpirationTime); + // Because this fiber did not complete, don't reset its expiration time. + if (workInProgress.effectTag & DidCapture) { + // Restarting an error boundary + stopFailedWorkTimer(workInProgress); + } else { + stopWorkTimer(workInProgress); + } + + if (next !== null) { + stopWorkTimer(workInProgress); + next.effectTag &= HostEffectMask; + return next; + } + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its effect list. + returnFiber.firstEffect = returnFiber.lastEffect = null; + returnFiber.effectTag |= Incomplete; + } + + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + return siblingFiber; + } else if (returnFiber !== null) { + // If there's no more work in this returnFiber. Complete the returnFiber. + workInProgress = returnFiber; + continue; + } else { + return null; + } + } + } + + // Without this explicit null return Flow complains of invalid return type + // TODO Remove the above while(true) loop + // eslint-disable-next-line no-unreachable + return null; +} + +function performUnitOfWork(workInProgress) { + // The current, flushed, state of this fiber is the alternate. + // Ideally nothing should rely on this, but relying on it here + // means that we don't need an additional field on the work in + // progress. + var current$$1 = workInProgress.alternate; + + // See if beginning this work spawns more work. + startWorkTimer(workInProgress); + var next = void 0; + if (enableProfilerTimer) { + if (workInProgress.mode & ProfileMode) { + startProfilerTimer(workInProgress); + } + + next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); + workInProgress.memoizedProps = workInProgress.pendingProps; + + if (workInProgress.mode & ProfileMode) { + // Record the render duration assuming we didn't bailout (or error). + stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true); + } + } else { + next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); + workInProgress.memoizedProps = workInProgress.pendingProps; + } + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(workInProgress); + } + + ReactCurrentOwner$1.current = null; + + return next; +} + +function workLoop(isYieldy) { + if (!isYieldy) { + // Flush work without yielding + while (nextUnitOfWork !== null) { + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } + } else { + // Flush asynchronous work until there's a higher priority event + while (nextUnitOfWork !== null && !shouldYieldToRenderer()) { + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + } + } +} + +function renderRoot(root, isYieldy) { + !!isWorking ? reactProdInvariant('243') : void 0; + + flushPassiveEffects$1(); + + isWorking = true; + var previousDispatcher = ReactCurrentDispatcher.current; + ReactCurrentDispatcher.current = ContextOnlyDispatcher; + + var expirationTime = root.nextExpirationTimeToWorkOn; + + // Check if we're starting from a fresh stack, or if we're resuming from + // previously yielded work. + if (expirationTime !== nextRenderExpirationTime || root !== nextRoot || nextUnitOfWork === null) { + // Reset the stack and start working from the root. + resetStack(); + nextRoot = root; + nextRenderExpirationTime = expirationTime; + nextUnitOfWork = createWorkInProgress(nextRoot.current, null, nextRenderExpirationTime); + root.pendingCommitExpirationTime = NoWork; + + if (enableSchedulerTracing) { + // Determine which interactions this batch of work currently includes, + // So that we can accurately attribute time spent working on it, + var interactions = new Set(); + root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { + if (scheduledExpirationTime >= expirationTime) { + scheduledInteractions.forEach(function (interaction) { + return interactions.add(interaction); + }); + } + }); + + // Store the current set of interactions on the FiberRoot for a few reasons: + // We can re-use it in hot functions like renderRoot() without having to recalculate it. + // We will also use it in commitWork() to pass to any Profiler onRender() hooks. + // This also provides DevTools with a way to access it when the onCommitRoot() hook is called. + root.memoizedInteractions = interactions; + + if (interactions.size > 0) { + var subscriber = __subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(expirationTime, root.interactionThreadID); + try { + subscriber.onWorkStarted(interactions, threadID); + } catch (error) { + // Work thrown by an interaction tracing subscriber should be rethrown, + // But only once it's safe (to avoid leaving the scheduler in an invalid state). + // Store the error for now and we'll re-throw in finishRendering(). + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } + } + } + } + } + + var prevInteractions = null; + if (enableSchedulerTracing) { + // We're about to start new traced work. + // Restore pending interactions so cascading work triggered during the render phase will be accounted for. + prevInteractions = __interactionsRef.current; + __interactionsRef.current = root.memoizedInteractions; + } + + var didFatal = false; + + startWorkLoopTimer(nextUnitOfWork); + + do { + try { + workLoop(isYieldy); + } catch (thrownValue) { + resetContextDependences(); + resetHooks(); + + // Reset in case completion throws. + // This is only used in DEV and when replaying is on. + if (nextUnitOfWork === null) { + // This is a fatal error. + didFatal = true; + onUncaughtError(thrownValue); + } else { + if (enableProfilerTimer && nextUnitOfWork.mode & ProfileMode) { + // Record the time spent rendering before an error was thrown. + // This avoids inaccurate Profiler durations in the case of a suspended render. + stopProfilerTimerIfRunningAndRecordDelta(nextUnitOfWork, true); + } + + !(nextUnitOfWork !== null) ? reactProdInvariant('271') : void 0; + + var sourceFiber = nextUnitOfWork; + var returnFiber = sourceFiber.return; + if (returnFiber === null) { + // This is the root. The root could capture its own errors. However, + // we don't know if it errors before or after we pushed the host + // context. This information is needed to avoid a stack mismatch. + // Because we're not sure, treat this as a fatal error. We could track + // which phase it fails in, but doesn't seem worth it. At least + // for now. + didFatal = true; + onUncaughtError(thrownValue); + } else { + throwException(root, returnFiber, sourceFiber, thrownValue, nextRenderExpirationTime); + nextUnitOfWork = completeUnitOfWork(sourceFiber); + continue; + } + } + } + break; + } while (true); + + if (enableSchedulerTracing) { + // Traced work is done for now; restore the previous interactions. + __interactionsRef.current = prevInteractions; + } + + // We're done performing work. Time to clean up. + isWorking = false; + ReactCurrentDispatcher.current = previousDispatcher; + resetContextDependences(); + resetHooks(); + + // Yield back to main thread. + if (didFatal) { + var _didCompleteRoot = false; + stopWorkLoopTimer(interruptedBy, _didCompleteRoot); + interruptedBy = null; + // There was a fatal error. + nextRoot = null; + onFatal(root); + return; + } + + if (nextUnitOfWork !== null) { + // There's still remaining async work in this tree, but we ran out of time + // in the current frame. Yield back to the renderer. Unless we're + // interrupted by a higher priority update, we'll continue later from where + // we left off. + var _didCompleteRoot2 = false; + stopWorkLoopTimer(interruptedBy, _didCompleteRoot2); + interruptedBy = null; + onYield(root); + return; + } + + // We completed the whole tree. + var didCompleteRoot = true; + stopWorkLoopTimer(interruptedBy, didCompleteRoot); + var rootWorkInProgress = root.current.alternate; + !(rootWorkInProgress !== null) ? reactProdInvariant('281') : void 0; + + // `nextRoot` points to the in-progress root. A non-null value indicates + // that we're in the middle of an async render. Set it to null to indicate + // there's no more work to be done in the current batch. + nextRoot = null; + interruptedBy = null; + + if (nextRenderDidError) { + // There was an error + if (hasLowerPriorityWork(root, expirationTime)) { + // There's lower priority work. If so, it may have the effect of fixing + // the exception that was just thrown. Exit without committing. This is + // similar to a suspend, but without a timeout because we're not waiting + // for a promise to resolve. React will restart at the lower + // priority level. + markSuspendedPriorityLevel(root, expirationTime); + var suspendedExpirationTime = expirationTime; + var rootExpirationTime = root.expirationTime; + onSuspend(root, rootWorkInProgress, suspendedExpirationTime, rootExpirationTime, -1 // Indicates no timeout + ); + return; + } else if ( + // There's no lower priority work, but we're rendering asynchronously. + // Synchronously attempt to render the same level one more time. This is + // similar to a suspend, but without a timeout because we're not waiting + // for a promise to resolve. + !root.didError && isYieldy) { + root.didError = true; + var _suspendedExpirationTime = root.nextExpirationTimeToWorkOn = expirationTime; + var _rootExpirationTime = root.expirationTime = Sync; + onSuspend(root, rootWorkInProgress, _suspendedExpirationTime, _rootExpirationTime, -1 // Indicates no timeout + ); + return; + } + } + + if (isYieldy && nextLatestAbsoluteTimeoutMs !== -1) { + // The tree was suspended. + var _suspendedExpirationTime2 = expirationTime; + markSuspendedPriorityLevel(root, _suspendedExpirationTime2); + + // Find the earliest uncommitted expiration time in the tree, including + // work that is suspended. The timeout threshold cannot be longer than + // the overall expiration. + var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, expirationTime); + var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); + if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) { + nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs; + } + + // Subtract the current time from the absolute timeout to get the number + // of milliseconds until the timeout. In other words, convert an absolute + // timestamp to a relative time. This is the value that is passed + // to `setTimeout`. + var currentTimeMs = expirationTimeToMs(requestCurrentTime()); + var msUntilTimeout = nextLatestAbsoluteTimeoutMs - currentTimeMs; + msUntilTimeout = msUntilTimeout < 0 ? 0 : msUntilTimeout; + + // TODO: Account for the Just Noticeable Difference + + var _rootExpirationTime2 = root.expirationTime; + onSuspend(root, rootWorkInProgress, _suspendedExpirationTime2, _rootExpirationTime2, msUntilTimeout); + return; + } + + // Ready to commit. + onComplete(root, rootWorkInProgress, expirationTime); +} + +function captureCommitPhaseError(sourceFiber, value) { + var expirationTime = Sync; + var fiber = sourceFiber.return; + while (fiber !== null) { + switch (fiber.tag) { + case ClassComponent: + var ctor = fiber.type; + var instance = fiber.stateNode; + if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { + var errorInfo = createCapturedValue(value, sourceFiber); + var update = createClassErrorUpdate(fiber, errorInfo, expirationTime); + enqueueUpdate(fiber, update); + scheduleWork(fiber, expirationTime); + return; + } + break; + case HostRoot: + { + var _errorInfo = createCapturedValue(value, sourceFiber); + var _update = createRootErrorUpdate(fiber, _errorInfo, expirationTime); + enqueueUpdate(fiber, _update); + scheduleWork(fiber, expirationTime); + return; + } + } + fiber = fiber.return; + } + + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + var rootFiber = sourceFiber; + var _errorInfo2 = createCapturedValue(value, rootFiber); + var _update2 = createRootErrorUpdate(rootFiber, _errorInfo2, expirationTime); + enqueueUpdate(rootFiber, _update2); + scheduleWork(rootFiber, expirationTime); + } +} + +function computeThreadID(expirationTime, interactionThreadID) { + // Interaction threads are unique per root and expiration time. + return expirationTime * 1000 + interactionThreadID; +} + +function computeExpirationForFiber(currentTime, fiber) { + var priorityLevel = unstable_getCurrentPriorityLevel(); + + var expirationTime = void 0; + if ((fiber.mode & ConcurrentMode) === NoContext) { + // Outside of concurrent mode, updates are always synchronous. + expirationTime = Sync; + } else if (isWorking && !isCommitting$1) { + // During render phase, updates expire during as the current render. + expirationTime = nextRenderExpirationTime; + } else { + switch (priorityLevel) { + case unstable_ImmediatePriority: + expirationTime = Sync; + break; + case unstable_UserBlockingPriority: + expirationTime = computeInteractiveExpiration(currentTime); + break; + case unstable_NormalPriority: + // This is a normal, concurrent update + expirationTime = computeAsyncExpiration(currentTime); + break; + case unstable_LowPriority: + case unstable_IdlePriority: + expirationTime = Never; + break; + default: + reactProdInvariant('313'); + } + + // If we're in the middle of rendering a tree, do not update at the same + // expiration time that is already rendering. + if (nextRoot !== null && expirationTime === nextRenderExpirationTime) { + expirationTime -= 1; + } + } + + // Keep track of the lowest pending interactive expiration time. This + // allows us to synchronously flush all interactive updates + // when needed. + // TODO: Move this to renderer? + return expirationTime; +} + +function renderDidSuspend(root, absoluteTimeoutMs, suspendedTime) { + // Schedule the timeout. + if (absoluteTimeoutMs >= 0 && nextLatestAbsoluteTimeoutMs < absoluteTimeoutMs) { + nextLatestAbsoluteTimeoutMs = absoluteTimeoutMs; + } +} + +function renderDidError() { + nextRenderDidError = true; +} + +function pingSuspendedRoot(root, thenable, pingTime) { + // A promise that previously suspended React from committing has resolved. + // If React is still suspended, try again at the previous level (pingTime). + + var pingCache = root.pingCache; + if (pingCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(thenable); + } + + if (nextRoot !== null && nextRenderExpirationTime === pingTime) { + // Received a ping at the same priority level at which we're currently + // rendering. Restart from the root. + nextRoot = null; + } else { + // Confirm that the root is still suspended at this level. Otherwise exit. + if (isPriorityLevelSuspended(root, pingTime)) { + // Ping at the original level + markPingedPriorityLevel(root, pingTime); + var rootExpirationTime = root.expirationTime; + if (rootExpirationTime !== NoWork) { + requestWork(root, rootExpirationTime); + } + } + } +} + +function retryTimedOutBoundary(boundaryFiber, thenable) { + // The boundary fiber (a Suspense component) previously timed out and was + // rendered in its fallback state. One of the promises that suspended it has + // resolved, which means at least part of the tree was likely unblocked. Try + var retryCache = void 0; + if (enableSuspenseServerRenderer) { + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + break; + case DehydratedSuspenseComponent: + retryCache = boundaryFiber.memoizedState; + break; + default: + reactProdInvariant('314'); + } + } else { + retryCache = boundaryFiber.stateNode; + } + if (retryCache !== null) { + // The thenable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(thenable); + } + + var currentTime = requestCurrentTime(); + var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); + var root = scheduleWorkToRoot(boundaryFiber, retryTime); + if (root !== null) { + markPendingPriorityLevel(root, retryTime); + var rootExpirationTime = root.expirationTime; + if (rootExpirationTime !== NoWork) { + requestWork(root, rootExpirationTime); + } + } +} + +function scheduleWorkToRoot(fiber, expirationTime) { + recordScheduleUpdate(); + + if (fiber.expirationTime < expirationTime) { + fiber.expirationTime = expirationTime; + } + var alternate = fiber.alternate; + if (alternate !== null && alternate.expirationTime < expirationTime) { + alternate.expirationTime = expirationTime; + } + // Walk the parent path to the root and update the child expiration time. + var node = fiber.return; + var root = null; + if (node === null && fiber.tag === HostRoot) { + root = fiber.stateNode; + } else { + while (node !== null) { + alternate = node.alternate; + if (node.childExpirationTime < expirationTime) { + node.childExpirationTime = expirationTime; + if (alternate !== null && alternate.childExpirationTime < expirationTime) { + alternate.childExpirationTime = expirationTime; + } + } else if (alternate !== null && alternate.childExpirationTime < expirationTime) { + alternate.childExpirationTime = expirationTime; + } + if (node.return === null && node.tag === HostRoot) { + root = node.stateNode; + break; + } + node = node.return; + } + } + + if (enableSchedulerTracing) { + if (root !== null) { + var interactions = __interactionsRef.current; + if (interactions.size > 0) { + var pendingInteractionMap = root.pendingInteractionMap; + var pendingInteractions = pendingInteractionMap.get(expirationTime); + if (pendingInteractions != null) { + interactions.forEach(function (interaction) { + if (!pendingInteractions.has(interaction)) { + // Update the pending async work count for previously unscheduled interaction. + interaction.__count++; + } + + pendingInteractions.add(interaction); + }); + } else { + pendingInteractionMap.set(expirationTime, new Set(interactions)); + + // Update the pending async work count for the current interactions. + interactions.forEach(function (interaction) { + interaction.__count++; + }); + } + + var subscriber = __subscriberRef.current; + if (subscriber !== null) { + var threadID = computeThreadID(expirationTime, root.interactionThreadID); + subscriber.onWorkScheduled(interactions, threadID); + } + } + } + } + return root; +} + + + +function scheduleWork(fiber, expirationTime) { + var root = scheduleWorkToRoot(fiber, expirationTime); + if (root === null) { + return; + } + + if (!isWorking && nextRenderExpirationTime !== NoWork && expirationTime > nextRenderExpirationTime) { + // This is an interruption. (Used for performance tracking.) + interruptedBy = fiber; + resetStack(); + } + markPendingPriorityLevel(root, expirationTime); + if ( + // If we're in the render phase, we don't need to schedule this root + // for an update, because we'll do it before we exit... + !isWorking || isCommitting$1 || + // ...unless this is a different root than the one we're rendering. + nextRoot !== root) { + var rootExpirationTime = root.expirationTime; + requestWork(root, rootExpirationTime); + } + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + // Reset this back to zero so subsequent updates don't throw. + nestedUpdateCount = 0; + reactProdInvariant('185'); + } +} + +function syncUpdates(fn, a, b, c, d) { + return unstable_runWithPriority(unstable_ImmediatePriority, function () { + return fn(a, b, c, d); + }); +} + +// TODO: Everything below this is written as if it has been lifted to the +// renderers. I'll do this in a follow-up. + +// Linked-list of roots +var firstScheduledRoot = null; +var lastScheduledRoot = null; + +var callbackExpirationTime = NoWork; +var callbackID = void 0; +var isRendering = false; +var nextFlushedRoot = null; +var nextFlushedExpirationTime = NoWork; +var hasUnhandledError = false; +var unhandledError = null; + +var isBatchingUpdates = false; +var isUnbatchingUpdates = false; + +var completedBatches = null; + +var originalStartTimeMs = now(); +var currentRendererTime = msToExpirationTime(originalStartTimeMs); +var currentSchedulerTime = currentRendererTime; + +// Use these to prevent an infinite loop of nested updates +var NESTED_UPDATE_LIMIT = 50; +var nestedUpdateCount = 0; +var lastCommittedRootDuringThisBatch = null; + +function recomputeCurrentRendererTime() { + var currentTimeMs = now() - originalStartTimeMs; + currentRendererTime = msToExpirationTime(currentTimeMs); +} + +function scheduleCallbackWithExpirationTime(root, expirationTime) { + if (callbackExpirationTime !== NoWork) { + // A callback is already scheduled. Check its expiration time (timeout). + if (expirationTime < callbackExpirationTime) { + // Existing callback has sufficient timeout. Exit. + return; + } else { + if (callbackID !== null) { + // Existing callback has insufficient timeout. Cancel and schedule a + // new one. + cancelDeferredCallback$$1(callbackID); + } + } + // The request callback timer is already running. Don't start a new one. + } else { + startRequestCallbackTimer(); + } + + callbackExpirationTime = expirationTime; + var currentMs = now() - originalStartTimeMs; + var expirationTimeMs = expirationTimeToMs(expirationTime); + var timeout = expirationTimeMs - currentMs; + callbackID = scheduleDeferredCallback$$1(performAsyncWork, { timeout: timeout }); +} + +// For every call to renderRoot, one of onFatal, onComplete, onSuspend, and +// onYield is called upon exiting. We use these in lieu of returning a tuple. +// I've also chosen not to inline them into renderRoot because these will +// eventually be lifted into the renderer. +function onFatal(root) { + root.finishedWork = null; +} + +function onComplete(root, finishedWork, expirationTime) { + root.pendingCommitExpirationTime = expirationTime; + root.finishedWork = finishedWork; +} + +function onSuspend(root, finishedWork, suspendedExpirationTime, rootExpirationTime, msUntilTimeout) { + root.expirationTime = rootExpirationTime; + if (msUntilTimeout === 0 && !shouldYieldToRenderer()) { + // Don't wait an additional tick. Commit the tree immediately. + root.pendingCommitExpirationTime = suspendedExpirationTime; + root.finishedWork = finishedWork; + } else if (msUntilTimeout > 0) { + // Wait `msUntilTimeout` milliseconds before committing. + root.timeoutHandle = scheduleTimeout(onTimeout.bind(null, root, finishedWork, suspendedExpirationTime), msUntilTimeout); + } +} + +function onYield(root) { + root.finishedWork = null; +} + +function onTimeout(root, finishedWork, suspendedExpirationTime) { + // The root timed out. Commit it. + root.pendingCommitExpirationTime = suspendedExpirationTime; + root.finishedWork = finishedWork; + // Read the current time before entering the commit phase. We can be + // certain this won't cause tearing related to batching of event updates + // because we're at the top of a timer event. + recomputeCurrentRendererTime(); + currentSchedulerTime = currentRendererTime; + flushRoot(root, suspendedExpirationTime); +} + +function onCommit(root, expirationTime) { + root.expirationTime = expirationTime; + root.finishedWork = null; +} + +function requestCurrentTime() { + // requestCurrentTime is called by the scheduler to compute an expiration + // time. + // + // Expiration times are computed by adding to the current time (the start + // time). However, if two updates are scheduled within the same event, we + // should treat their start times as simultaneous, even if the actual clock + // time has advanced between the first and second call. + + // In other words, because expiration times determine how updates are batched, + // we want all updates of like priority that occur within the same event to + // receive the same expiration time. Otherwise we get tearing. + // + // We keep track of two separate times: the current "renderer" time and the + // current "scheduler" time. The renderer time can be updated whenever; it + // only exists to minimize the calls performance.now. + // + // But the scheduler time can only be updated if there's no pending work, or + // if we know for certain that we're not in the middle of an event. + + if (isRendering) { + // We're already rendering. Return the most recently read time. + return currentSchedulerTime; + } + // Check if there's pending work. + findHighestPriorityRoot(); + if (nextFlushedExpirationTime === NoWork || nextFlushedExpirationTime === Never) { + // If there's no pending work, or if the pending work is offscreen, we can + // read the current time without risk of tearing. + recomputeCurrentRendererTime(); + currentSchedulerTime = currentRendererTime; + return currentSchedulerTime; + } + // There's already pending work. We might be in the middle of a browser + // event. If we were to read the current time, it could cause multiple updates + // within the same event to receive different expiration times, leading to + // tearing. Return the last read time. During the next idle callback, the + // time will be updated. + return currentSchedulerTime; +} + +// requestWork is called by the scheduler whenever a root receives an update. +// It's up to the renderer to call renderRoot at some point in the future. +function requestWork(root, expirationTime) { + addRootToSchedule(root, expirationTime); + if (isRendering) { + // Prevent reentrancy. Remaining work will be scheduled at the end of + // the currently rendering batch. + return; + } + + if (isBatchingUpdates) { + // Flush work at the end of the batch. + if (isUnbatchingUpdates) { + // ...unless we're inside unbatchedUpdates, in which case we should + // flush it now. + nextFlushedRoot = root; + nextFlushedExpirationTime = Sync; + performWorkOnRoot(root, Sync, false); + } + return; + } + + // TODO: Get rid of Sync and use current time? + if (expirationTime === Sync) { + performSyncWork(); + } else { + scheduleCallbackWithExpirationTime(root, expirationTime); + } +} + +function addRootToSchedule(root, expirationTime) { + // Add the root to the schedule. + // Check if this root is already part of the schedule. + if (root.nextScheduledRoot === null) { + // This root is not already scheduled. Add it. + root.expirationTime = expirationTime; + if (lastScheduledRoot === null) { + firstScheduledRoot = lastScheduledRoot = root; + root.nextScheduledRoot = root; + } else { + lastScheduledRoot.nextScheduledRoot = root; + lastScheduledRoot = root; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + } + } else { + // This root is already scheduled, but its priority may have increased. + var remainingExpirationTime = root.expirationTime; + if (expirationTime > remainingExpirationTime) { + // Update the priority. + root.expirationTime = expirationTime; + } + } +} + +function findHighestPriorityRoot() { + var highestPriorityWork = NoWork; + var highestPriorityRoot = null; + if (lastScheduledRoot !== null) { + var previousScheduledRoot = lastScheduledRoot; + var root = firstScheduledRoot; + while (root !== null) { + var remainingExpirationTime = root.expirationTime; + if (remainingExpirationTime === NoWork) { + // This root no longer has work. Remove it from the scheduler. + + // TODO: This check is redudant, but Flow is confused by the branch + // below where we set lastScheduledRoot to null, even though we break + // from the loop right after. + !(previousScheduledRoot !== null && lastScheduledRoot !== null) ? reactProdInvariant('244') : void 0; + if (root === root.nextScheduledRoot) { + // This is the only root in the list. + root.nextScheduledRoot = null; + firstScheduledRoot = lastScheduledRoot = null; + break; + } else if (root === firstScheduledRoot) { + // This is the first root in the list. + var next = root.nextScheduledRoot; + firstScheduledRoot = next; + lastScheduledRoot.nextScheduledRoot = next; + root.nextScheduledRoot = null; + } else if (root === lastScheduledRoot) { + // This is the last root in the list. + lastScheduledRoot = previousScheduledRoot; + lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; + root.nextScheduledRoot = null; + break; + } else { + previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; + root.nextScheduledRoot = null; + } + root = previousScheduledRoot.nextScheduledRoot; + } else { + if (remainingExpirationTime > highestPriorityWork) { + // Update the priority, if it's higher + highestPriorityWork = remainingExpirationTime; + highestPriorityRoot = root; + } + if (root === lastScheduledRoot) { + break; + } + if (highestPriorityWork === Sync) { + // Sync is highest priority by definition so + // we can stop searching. + break; + } + previousScheduledRoot = root; + root = root.nextScheduledRoot; + } + } + } + + nextFlushedRoot = highestPriorityRoot; + nextFlushedExpirationTime = highestPriorityWork; +} + +// TODO: This wrapper exists because many of the older tests (the ones that use +// flushDeferredPri) rely on the number of times `shouldYield` is called. We +// should get rid of it. +var didYield = false; +function shouldYieldToRenderer() { + if (didYield) { + return true; + } + if (shouldYield$$1()) { + didYield = true; + return true; + } + return false; +} + +function performAsyncWork() { + try { + if (!shouldYieldToRenderer()) { + // The callback timed out. That means at least one update has expired. + // Iterate through the root schedule. If they contain expired work, set + // the next render expiration time to the current time. This has the effect + // of flushing all expired work in a single batch, instead of flushing each + // level one at a time. + if (firstScheduledRoot !== null) { + recomputeCurrentRendererTime(); + var root = firstScheduledRoot; + do { + didExpireAtExpirationTime(root, currentRendererTime); + // The root schedule is circular, so this is never null. + root = root.nextScheduledRoot; + } while (root !== firstScheduledRoot); + } + } + performWork(NoWork, true); + } finally { + didYield = false; + } +} + +function performSyncWork() { + performWork(Sync, false); +} + +function performWork(minExpirationTime, isYieldy) { + // Keep working on roots until there's no more work, or until there's a higher + // priority event. + findHighestPriorityRoot(); + + if (isYieldy) { + recomputeCurrentRendererTime(); + currentSchedulerTime = currentRendererTime; + + if (enableUserTimingAPI) { + var didExpire = nextFlushedExpirationTime > currentRendererTime; + var timeout = expirationTimeToMs(nextFlushedExpirationTime); + stopRequestCallbackTimer(didExpire, timeout); + } + + while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime && !(didYield && currentRendererTime > nextFlushedExpirationTime)) { + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, currentRendererTime > nextFlushedExpirationTime); + findHighestPriorityRoot(); + recomputeCurrentRendererTime(); + currentSchedulerTime = currentRendererTime; + } + } else { + while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime) { + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); + findHighestPriorityRoot(); + } + } + + // We're done flushing work. Either we ran out of time in this callback, + // or there's no more work left with sufficient priority. + + // If we're inside a callback, set this to false since we just completed it. + if (isYieldy) { + callbackExpirationTime = NoWork; + callbackID = null; + } + // If there's work left over, schedule a new callback. + if (nextFlushedExpirationTime !== NoWork) { + scheduleCallbackWithExpirationTime(nextFlushedRoot, nextFlushedExpirationTime); + } + + // Clean-up. + finishRendering(); +} + +function flushRoot(root, expirationTime) { + !!isRendering ? reactProdInvariant('253') : void 0; + // Perform work on root as if the given expiration time is the current time. + // This has the effect of synchronously flushing all work up to and + // including the given time. + nextFlushedRoot = root; + nextFlushedExpirationTime = expirationTime; + performWorkOnRoot(root, expirationTime, false); + // Flush any sync work that was scheduled by lifecycles + performSyncWork(); +} + +function finishRendering() { + nestedUpdateCount = 0; + lastCommittedRootDuringThisBatch = null; + + if (completedBatches !== null) { + var batches = completedBatches; + completedBatches = null; + for (var i = 0; i < batches.length; i++) { + var batch = batches[i]; + try { + batch._onComplete(); + } catch (error) { + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } + } + } + } + + if (hasUnhandledError) { + var error = unhandledError; + unhandledError = null; + hasUnhandledError = false; + throw error; + } +} + +function performWorkOnRoot(root, expirationTime, isYieldy) { + !!isRendering ? reactProdInvariant('245') : void 0; + + isRendering = true; + + // Check if this is async work or sync/expired work. + if (!isYieldy) { + // Flush work without yielding. + // TODO: Non-yieldy work does not necessarily imply expired work. A renderer + // may want to perform some work without yielding, but also without + // requiring the root to complete (by triggering placeholders). + + var finishedWork = root.finishedWork; + if (finishedWork !== null) { + // This root is already complete. We can commit it. + completeRoot(root, finishedWork, expirationTime); + } else { + root.finishedWork = null; + // If this root previously suspended, clear its existing timeout, since + // we're about to try rendering again. + var timeoutHandle = root.timeoutHandle; + if (timeoutHandle !== noTimeout) { + root.timeoutHandle = noTimeout; + // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + cancelTimeout(timeoutHandle); + } + renderRoot(root, isYieldy); + finishedWork = root.finishedWork; + if (finishedWork !== null) { + // We've completed the root. Commit it. + completeRoot(root, finishedWork, expirationTime); + } + } + } else { + // Flush async work. + var _finishedWork = root.finishedWork; + if (_finishedWork !== null) { + // This root is already complete. We can commit it. + completeRoot(root, _finishedWork, expirationTime); + } else { + root.finishedWork = null; + // If this root previously suspended, clear its existing timeout, since + // we're about to try rendering again. + var _timeoutHandle = root.timeoutHandle; + if (_timeoutHandle !== noTimeout) { + root.timeoutHandle = noTimeout; + // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above + cancelTimeout(_timeoutHandle); + } + renderRoot(root, isYieldy); + _finishedWork = root.finishedWork; + if (_finishedWork !== null) { + // We've completed the root. Check the if we should yield one more time + // before committing. + if (!shouldYieldToRenderer()) { + // Still time left. Commit the root. + completeRoot(root, _finishedWork, expirationTime); + } else { + // There's no time left. Mark this root as complete. We'll come + // back and commit it later. + root.finishedWork = _finishedWork; + } + } + } + } + + isRendering = false; +} + +function completeRoot(root, finishedWork, expirationTime) { + // Check if there's a batch that matches this expiration time. + var firstBatch = root.firstBatch; + if (firstBatch !== null && firstBatch._expirationTime >= expirationTime) { + if (completedBatches === null) { + completedBatches = [firstBatch]; + } else { + completedBatches.push(firstBatch); + } + if (firstBatch._defer) { + // This root is blocked from committing by a batch. Unschedule it until + // we receive another update. + root.finishedWork = finishedWork; + root.expirationTime = NoWork; + return; + } + } + + // Commit the root. + root.finishedWork = null; + + // Check if this is a nested update (a sync update scheduled during the + // commit phase). + if (root === lastCommittedRootDuringThisBatch) { + // If the next root is the same as the previous root, this is a nested + // update. To prevent an infinite loop, increment the nested update count. + nestedUpdateCount++; + } else { + // Reset whenever we switch roots. + lastCommittedRootDuringThisBatch = root; + nestedUpdateCount = 0; + } + unstable_runWithPriority(unstable_ImmediatePriority, function () { + commitRoot(root, finishedWork); + }); +} + +function onUncaughtError(error) { + !(nextFlushedRoot !== null) ? reactProdInvariant('246') : void 0; + // Unschedule this root so we don't work on it again until there's + // another update. + nextFlushedRoot.expirationTime = NoWork; + if (!hasUnhandledError) { + hasUnhandledError = true; + unhandledError = error; + } +} + +// TODO: Batching should be implemented at the renderer level, not inside +// the reconciler. +function batchedUpdates(fn, a) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + return fn(a); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } + } +} + +// TODO: Batching should be implemented at the renderer level, not within +// the reconciler. +function flushSync(fn, a) { + !!isRendering ? reactProdInvariant('187') : void 0; + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + return syncUpdates(fn, a); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + performSyncWork(); + } +} + +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + + if (fiber.tag === ClassComponent) { + var Component = fiber.type; + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } + } + + return parentContext; +} + +function scheduleRootUpdate(current$$1, element, expirationTime, callback) { + var update = createUpdate(expirationTime); + // Caution: React DevTools currently depends on this property + // being called "element". + update.payload = { element: element }; + + callback = callback === undefined ? null : callback; + if (callback !== null) { + update.callback = callback; + } + + flushPassiveEffects$1(); + enqueueUpdate(current$$1, update); + scheduleWork(current$$1, expirationTime); + + return expirationTime; +} + +function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) { + // TODO: If this is a nested container, this won't be the root. + var current$$1 = container.current; + + var context = getContextForSubtree(parentComponent); + if (container.context === null) { + container.context = context; + } else { + container.pendingContext = context; + } + + return scheduleRootUpdate(current$$1, element, expirationTime, callback); +} + +function createContainer(containerInfo, isConcurrent, hydrate) { + return createFiberRoot(containerInfo, isConcurrent, hydrate); +} + +function updateContainer(element, container, parentComponent, callback) { + var current$$1 = container.current; + var currentTime = requestCurrentTime(); + var expirationTime = computeExpirationForFiber(currentTime, current$$1); + return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback); +} + +function getPublicRootInstance(container) { + var containerFiber = container.current; + if (!containerFiber.child) { + return null; + } + switch (containerFiber.child.tag) { + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); + default: + return containerFiber.child.stateNode; + } +} + + + +var overrideProps = null; + +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; + + + return injectInternals(_assign({}, devToolsConfig, { + overrideProps: overrideProps, + currentDispatcherRef: ReactCurrentDispatcher, + findHostInstanceByFiber: function (fiber) { + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; + }, + findFiberByHostInstance: function (instance) { + if (!findFiberByHostInstance) { + // Might not be implemented by the renderer. + return null; + } + return findFiberByHostInstance(instance); + } + })); +} + +// This file intentionally does *not* have the Flow annotation. +// Don't add it. See `./inline-typed.js` for an explanation. + +// TODO: this is special because it gets imported during build. + +var ReactVersion = '16.8.6'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } + +// for .act's return value + + +var defaultTestOptions = { + createNodeMock: function () { + return null; + } +}; + +function toJSON(inst) { + if (inst.isHidden) { + // Omit timed out children from output entirely. This seems like the least + // surprising behavior. We could perhaps add a separate API that includes + // them, if it turns out people need it. + return null; + } + switch (inst.tag) { + case 'TEXT': + return inst.text; + case 'INSTANCE': + { + /* eslint-disable no-unused-vars */ + // We don't include the `children` prop in JSON. + // Instead, we will include the actual rendered children. + var _inst$props = inst.props, + _children = _inst$props.children, + _props = _objectWithoutProperties(_inst$props, ['children']); + /* eslint-enable */ + + + var renderedChildren = null; + if (inst.children && inst.children.length) { + for (var i = 0; i < inst.children.length; i++) { + var renderedChild = toJSON(inst.children[i]); + if (renderedChild !== null) { + if (renderedChildren === null) { + renderedChildren = [renderedChild]; + } else { + renderedChildren.push(renderedChild); + } + } + } + } + var json = { + type: inst.type, + props: _props, + children: renderedChildren + }; + Object.defineProperty(json, '$$typeof', { + value: Symbol.for('react.test.json') + }); + return json; + } + default: + throw new Error('Unexpected node type in toJSON: ' + inst.tag); + } +} + +function childrenToTree(node) { + if (!node) { + return null; + } + var children = nodeAndSiblingsArray(node); + if (children.length === 0) { + return null; + } else if (children.length === 1) { + return toTree(children[0]); + } + return flatten(children.map(toTree)); +} + +function nodeAndSiblingsArray(nodeWithSibling) { + var array = []; + var node = nodeWithSibling; + while (node != null) { + array.push(node); + node = node.sibling; + } + return array; +} + +function flatten(arr) { + var result = []; + var stack = [{ i: 0, array: arr }]; + while (stack.length) { + var n = stack.pop(); + while (n.i < n.array.length) { + var el = n.array[n.i]; + n.i += 1; + if (Array.isArray(el)) { + stack.push(n); + stack.push({ i: 0, array: el }); + break; + } + result.push(el); + } + } + return result; +} + +function toTree(node) { + if (node == null) { + return null; + } + switch (node.tag) { + case HostRoot: + return childrenToTree(node.child); + case HostPortal: + return childrenToTree(node.child); + case ClassComponent: + return { + nodeType: 'component', + type: node.type, + props: _assign({}, node.memoizedProps), + instance: node.stateNode, + rendered: childrenToTree(node.child) + }; + case FunctionComponent: + case SimpleMemoComponent: + return { + nodeType: 'component', + type: node.type, + props: _assign({}, node.memoizedProps), + instance: null, + rendered: childrenToTree(node.child) + }; + case HostComponent: + { + return { + nodeType: 'host', + type: node.type, + props: _assign({}, node.memoizedProps), + instance: null, // TODO: use createNodeMock here somehow? + rendered: flatten(nodeAndSiblingsArray(node.child).map(toTree)) + }; + } + case HostText: + return node.stateNode.text; + case Fragment: + case ContextProvider: + case ContextConsumer: + case Mode: + case Profiler: + case ForwardRef: + case MemoComponent: + case IncompleteClassComponent: + return childrenToTree(node.child); + default: + reactProdInvariant('214', node.tag); + } +} + +var validWrapperTypes = new Set([FunctionComponent, ClassComponent, HostComponent, ForwardRef, MemoComponent, SimpleMemoComponent, +// Normally skipped, but used when there's more than one root child. +HostRoot]); + +function getChildren(parent) { + var children = []; + var startingNode = parent; + var node = startingNode; + if (node.child === null) { + return children; + } + node.child.return = node; + node = node.child; + outer: while (true) { + var descend = false; + if (validWrapperTypes.has(node.tag)) { + children.push(wrapFiber(node)); + } else if (node.tag === HostText) { + children.push('' + node.memoizedProps); + } else { + descend = true; + } + if (descend && node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } + while (node.sibling === null) { + if (node.return === startingNode) { + break outer; + } + node = node.return; + } + node.sibling.return = node.return; + node = node.sibling; + } + return children; +} + +var ReactTestInstance = function () { + ReactTestInstance.prototype._currentFiber = function _currentFiber() { + // Throws if this component has been unmounted. + var fiber = findCurrentFiberUsingSlowPath(this._fiber); + !(fiber !== null) ? reactProdInvariant('224') : void 0; + return fiber; + }; + + function ReactTestInstance(fiber) { + _classCallCheck(this, ReactTestInstance); + + !validWrapperTypes.has(fiber.tag) ? reactProdInvariant('225', fiber.tag) : void 0; + this._fiber = fiber; + } + + // Custom search functions + ReactTestInstance.prototype.find = function find(predicate) { + return expectOne(this.findAll(predicate, { deep: false }), 'matching custom predicate: ' + predicate.toString()); + }; + + ReactTestInstance.prototype.findByType = function findByType(type) { + return expectOne(this.findAllByType(type, { deep: false }), 'with node type: "' + (type.displayName || type.name) + '"'); + }; + + ReactTestInstance.prototype.findByProps = function findByProps(props) { + return expectOne(this.findAllByProps(props, { deep: false }), 'with props: ' + JSON.stringify(props)); + }; + + ReactTestInstance.prototype.findAll = function findAll(predicate) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + return _findAll(this, predicate, options); + }; + + ReactTestInstance.prototype.findAllByType = function findAllByType(type) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + return _findAll(this, function (node) { + return node.type === type; + }, options); + }; + + ReactTestInstance.prototype.findAllByProps = function findAllByProps(props) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + return _findAll(this, function (node) { + return node.props && propsMatch(node.props, props); + }, options); + }; + + _createClass(ReactTestInstance, [{ + key: 'instance', + get: function () { + if (this._fiber.tag === HostComponent) { + return getPublicInstance(this._fiber.stateNode); + } else { + return this._fiber.stateNode; + } + } + }, { + key: 'type', + get: function () { + return this._fiber.type; + } + }, { + key: 'props', + get: function () { + return this._currentFiber().memoizedProps; + } + }, { + key: 'parent', + get: function () { + var parent = this._fiber.return; + while (parent !== null) { + if (validWrapperTypes.has(parent.tag)) { + if (parent.tag === HostRoot) { + // Special case: we only "materialize" instances for roots + // if they have more than a single child. So we'll check that now. + if (getChildren(parent).length < 2) { + return null; + } + } + return wrapFiber(parent); + } + parent = parent.return; + } + return null; + } + }, { + key: 'children', + get: function () { + return getChildren(this._currentFiber()); + } + }]); + + return ReactTestInstance; +}(); + +function _findAll(root, predicate, options) { + var deep = options ? options.deep : true; + var results = []; + + if (predicate(root)) { + results.push(root); + if (!deep) { + return results; + } + } + + root.children.forEach(function (child) { + if (typeof child === 'string') { + return; + } + results.push.apply(results, _findAll(child, predicate, options)); + }); + + return results; +} + +function expectOne(all, message) { + if (all.length === 1) { + return all[0]; + } + + var prefix = all.length === 0 ? 'No instances found ' : 'Expected 1 but found ' + all.length + ' instances '; + + throw new Error(prefix + message); +} + +function propsMatch(props, filter) { + for (var key in filter) { + if (props[key] !== filter[key]) { + return false; + } + } + return true; +} + +var ReactTestRendererFiber = { + create: function (element, options) { + var createNodeMock = defaultTestOptions.createNodeMock; + var isConcurrent = false; + if (typeof options === 'object' && options !== null) { + if (typeof options.createNodeMock === 'function') { + createNodeMock = options.createNodeMock; + } + if (options.unstable_isConcurrent === true) { + isConcurrent = true; + } + } + var container = { + children: [], + createNodeMock: createNodeMock, + tag: 'CONTAINER' + }; + var root = createContainer(container, isConcurrent, false); + !(root != null) ? reactProdInvariant('215') : void 0; + updateContainer(element, root, null, null); + + var entry = { + root: undefined, // makes flow happy + // we define a 'getter' for 'root' below using 'Object.defineProperty' + toJSON: function () { + if (root == null || root.current == null || container == null) { + return null; + } + if (container.children.length === 0) { + return null; + } + if (container.children.length === 1) { + return toJSON(container.children[0]); + } + if (container.children.length === 2 && container.children[0].isHidden === true && container.children[1].isHidden === false) { + // Omit timed out children from output entirely, including the fact that we + // temporarily wrap fallback and timed out children in an array. + return toJSON(container.children[1]); + } + var renderedChildren = null; + if (container.children && container.children.length) { + for (var i = 0; i < container.children.length; i++) { + var renderedChild = toJSON(container.children[i]); + if (renderedChild !== null) { + if (renderedChildren === null) { + renderedChildren = [renderedChild]; + } else { + renderedChildren.push(renderedChild); + } + } + } + } + return renderedChildren; + }, + toTree: function () { + if (root == null || root.current == null) { + return null; + } + return toTree(root.current); + }, + update: function (newElement) { + if (root == null || root.current == null) { + return; + } + updateContainer(newElement, root, null, null); + }, + unmount: function () { + if (root == null || root.current == null) { + return; + } + updateContainer(null, root, null, null); + container = null; + root = null; + }, + getInstance: function () { + if (root == null || root.current == null) { + return null; + } + return getPublicRootInstance(root); + }, + + + unstable_flushAll: flushAll, + unstable_flushSync: function (fn) { + clearYields(); + return flushSync(fn); + }, + + unstable_flushNumberOfYields: flushNumberOfYields, + unstable_clearYields: clearYields + }; + + Object.defineProperty(entry, 'root', { + configurable: true, + enumerable: true, + get: function () { + if (root === null) { + throw new Error("Can't access .root on unmounted test renderer"); + } + var children = getChildren(root.current); + if (children.length === 0) { + throw new Error("Can't access .root on unmounted test renderer"); + } else if (children.length === 1) { + // Normally, we skip the root and just give you the child. + return children[0]; + } else { + // However, we give you the root if there's more than one root child. + // We could make this the behavior for all cases but it would be a breaking change. + return wrapFiber(root.current); + } + } + }); + + return entry; + }, + + + unstable_yield: yieldValue, + unstable_clearYields: clearYields, + + /* eslint-disable camelcase */ + unstable_batchedUpdates: batchedUpdates, + /* eslint-enable camelcase */ + + unstable_setNowImplementation: setNowImplementation, + + act: function (callback) { + // note: keep these warning messages in sync with + // createNoop.js and ReactTestUtils.js + var result = batchedUpdates(callback); + flushPassiveEffects(); + // we want the user to not expect a return, + // but we want to warn if they use it like they can await on it. + return { + then: function () { + + } + }; + } +}; + +// root used to flush effects during .act() calls +var actRoot = createContainer({ + children: [], + createNodeMock: defaultTestOptions.createNodeMock, + tag: 'CONTAINER' +}, true, false); + +function flushPassiveEffects() { + // Trick to flush passive effects without exposing an internal API: + // Create a throwaway root and schedule a dummy update on it. + updateContainer(null, actRoot, null, null); +} + +var fiberToWrapper = new WeakMap(); +function wrapFiber(fiber) { + var wrapper = fiberToWrapper.get(fiber); + if (wrapper === undefined && fiber.alternate !== null) { + wrapper = fiberToWrapper.get(fiber.alternate); + } + if (wrapper === undefined) { + wrapper = new ReactTestInstance(fiber); + fiberToWrapper.set(fiber, wrapper); + } + return wrapper; +} + +// Enable ReactTestRenderer to be used to test DevTools integration. +injectIntoDevTools({ + findFiberByHostInstance: function () { + throw new Error('TestRenderer does not support findFiberByHostInstance()'); + }, + bundleType: 0, + version: ReactVersion, + rendererPackageName: 'react-test-renderer' +}); + + + +var ReactTestRenderer = ({ + default: ReactTestRendererFiber +}); + +var ReactTestRenderer$1 = ( ReactTestRenderer && ReactTestRendererFiber ) || ReactTestRenderer; + +// TODO: decide on the top-level export form. +// This is hacky but makes it work with both Rollup and Jest. +var reactTestRenderer = ReactTestRenderer$1.default || ReactTestRenderer$1; + +return reactTestRenderer; + +}))); |