diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 219cda440ac83..cb5c649f6e87e 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -d310d654a7c7aab6c8213da84ef36dfba82711b0 +cfc1274e3be5a93a4c93f8fb87f2109993afe1dd diff --git a/compiled/facebook-www/React-dev.modern.js b/compiled/facebook-www/React-dev.modern.js index 6b5154eef5b4b..7446ca9d7e3a2 100644 --- a/compiled/facebook-www/React-dev.modern.js +++ b/compiled/facebook-www/React-dev.modern.js @@ -27,7 +27,7 @@ if ( } "use strict"; -var ReactVersion = "18.3.0-www-modern-9bafe2f6"; +var ReactVersion = "18.3.0-www-modern-addde25e"; // ATTENTION // When adding new symbols to this file, diff --git a/compiled/facebook-www/ReactART-dev.classic.js b/compiled/facebook-www/ReactART-dev.classic.js index f5da1f8b17577..6ac85abd1cdc7 100644 --- a/compiled/facebook-www/ReactART-dev.classic.js +++ b/compiled/facebook-www/ReactART-dev.classic.js @@ -69,7 +69,7 @@ function _assertThisInitialized(self) { return self; } -var ReactVersion = "18.3.0-www-classic-d10ee72f"; +var ReactVersion = "18.3.0-www-classic-773bb029"; var LegacyRoot = 0; var ConcurrentRoot = 1; diff --git a/compiled/facebook-www/ReactART-prod.modern.js b/compiled/facebook-www/ReactART-prod.modern.js index 73465e7309f95..dbeb8785b1d29 100644 --- a/compiled/facebook-www/ReactART-prod.modern.js +++ b/compiled/facebook-www/ReactART-prod.modern.js @@ -9555,7 +9555,7 @@ var slice = Array.prototype.slice, return null; }, bundleType: 0, - version: "18.3.0-www-modern-ce2970c7", + version: "18.3.0-www-modern-990522b1", rendererPackageName: "react-art" }; var internals$jscomp$inline_1283 = { @@ -9586,7 +9586,7 @@ var internals$jscomp$inline_1283 = { scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-www-modern-ce2970c7" + reconcilerVersion: "18.3.0-www-modern-990522b1" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { var hook$jscomp$inline_1284 = __REACT_DEVTOOLS_GLOBAL_HOOK__; diff --git a/compiled/facebook-www/ReactDOM-dev.classic.js b/compiled/facebook-www/ReactDOM-dev.classic.js index 9f6d6acd56338..139223ff5502c 100644 --- a/compiled/facebook-www/ReactDOM-dev.classic.js +++ b/compiled/facebook-www/ReactDOM-dev.classic.js @@ -37,6 +37,7 @@ var dynamicFeatureFlags = require("ReactFeatureFlags"); var disableInputAttributeSyncing = dynamicFeatureFlags.disableInputAttributeSyncing, + disableIEWorkarounds = dynamicFeatureFlags.disableIEWorkarounds, enableTrustedTypesIntegration = dynamicFeatureFlags.enableTrustedTypesIntegration, replayFailedUnitOfWorkWithInvokeGuardedCallback = @@ -5412,7 +5413,8 @@ var canDiffStyleForHydrationWarning; // in that browser completely in favor of doing all that work. // See https://github.com/facebook/react/issues/11807 - canDiffStyleForHydrationWarning = canUseDOM && !document.documentMode; + canDiffStyleForHydrationWarning = + disableIEWorkarounds || (canUseDOM && !document.documentMode); } function validatePropertiesInDevelopment(type, props) { @@ -5605,7 +5607,11 @@ function setInitialDOMProperties( var nextHtml = nextProp ? nextProp[HTML] : undefined; if (nextHtml != null) { - setInnerHTML$1(domElement, nextHtml); + if (disableIEWorkarounds) { + domElement.innerHTML = nextHtml; + } else { + setInnerHTML$1(domElement, nextHtml); + } } } else if (propKey === CHILDREN) { if (typeof nextProp === "string") { @@ -5661,7 +5667,11 @@ function updateDOMProperties( if (propKey === STYLE$1) { setValueForStyles(domElement, propValue); } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { - setInnerHTML$1(domElement, propValue); + if (disableIEWorkarounds) { + domElement.innerHTML = propValue; + } else { + setInnerHTML$1(domElement, propValue); + } } else if (propKey === CHILDREN) { setTextContent(domElement, propValue); } else { @@ -9028,7 +9038,7 @@ var ContinuousEventPriority = InputContinuousLane; var DefaultEventPriority = DefaultLane; var IdleEventPriority = IdleLane; var currentUpdatePriority = NoLane; -function getCurrentUpdatePriority$1() { +function getCurrentUpdatePriority() { return currentUpdatePriority; } function setCurrentUpdatePriority(newPriority) { @@ -12057,7 +12067,6 @@ function isOwnedInstance(node) { return !!(node[internalHoistableMarker] || node[internalInstanceKey]); } -var restoreImpl = null; var restoreTarget = null; var restoreQueue = null; @@ -12071,24 +12080,18 @@ function restoreStateOfTarget(target) { return; } - if (typeof restoreImpl !== "function") { - throw new Error( - "setRestoreImplementation() needs to be called to handle a target for controlled " + - "events. This error is likely caused by a bug in React. Please file an issue." - ); - } - var stateNode = internalInstance.stateNode; // Guard against Fiber being unmounted. if (stateNode) { var props = getFiberCurrentPropsFromNode(stateNode); - restoreImpl(internalInstance.stateNode, internalInstance.type, props); + restoreControlledState( + internalInstance.stateNode, + internalInstance.type, + props + ); } } -function setRestoreImplementation(impl) { - restoreImpl = impl; -} function enqueueStateRestore(target) { if (restoreTarget) { if (restoreQueue) { @@ -12121,6681 +12124,5740 @@ function restoreStateIfNeeded() { } } -// the renderer. Such as when we're dispatching events or if third party -// libraries need to call batchedUpdates. Eventually, this API will go away when -// everything is batched by default. We'll then have a similar API to opt-out of -// scheduled work and instead do synchronous work. -// Defaults +var loggedTypeFailures = {}; +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; -var batchedUpdatesImpl = function (fn, bookkeeping) { - return fn(bookkeeping); -}; +function setCurrentlyValidatingElement(element) { + { + if (element) { + var owner = element._owner; + var stack = describeUnknownElementTypeFrameInDEV( + element.type, + element._source, + owner ? owner.type : null + ); + ReactDebugCurrentFrame.setExtraStackFrame(stack); + } else { + ReactDebugCurrentFrame.setExtraStackFrame(null); + } + } +} -var flushSyncImpl = function () {}; +function checkPropTypes(typeSpecs, values, location, componentName, element) { + { + // $FlowFixMe This is okay but Flow doesn't know it. + var has = Function.call.bind(hasOwnProperty); -var isInsideEventHandler = false; + for (var typeSpecName in typeSpecs) { + if (has(typeSpecs, typeSpecName)) { + var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to + // fail the render phase where it didn't fail before. So we log it. + // After these have been cleaned up, we'll let them throw. -function finishEventHandler() { - // Here we wait until all updates have propagated, which is important - // when using controlled components within layers: - // https://github.com/facebook/react/issues/1698 - // Then we restore state of any controlled component. - var controlledComponentsHavePendingUpdates = needsStateRestore(); + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + if (typeof typeSpecs[typeSpecName] !== "function") { + // eslint-disable-next-line react-internal/prod-error-codes + var err = Error( + (componentName || "React class") + + ": " + + location + + " type `" + + typeSpecName + + "` is invalid; " + + "it must be a function, usually from the `prop-types` package, but received `" + + typeof typeSpecs[typeSpecName] + + "`." + + "This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`." + ); + err.name = "Invariant Violation"; + throw err; + } - if (controlledComponentsHavePendingUpdates) { - // If a controlled event was fired, we may need to restore the state of - // the DOM node back to the controlled value. This is necessary when React - // bails out of the update without touching the DOM. - // TODO: Restore state in the microtask, after the discrete updates flush, - // instead of early flushing them here. - flushSyncImpl(); - restoreStateIfNeeded(); - } -} + error$1 = typeSpecs[typeSpecName]( + values, + typeSpecName, + componentName, + location, + null, + "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED" + ); + } catch (ex) { + error$1 = ex; + } -function batchedUpdates$1(fn, a, b) { - if (isInsideEventHandler) { - // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. - return fn(a, b); - } + if (error$1 && !(error$1 instanceof Error)) { + setCurrentlyValidatingElement(element); - isInsideEventHandler = true; + error( + "%s: type specification of %s" + + " `%s` is invalid; the type checker " + + "function must return `null` or an `Error` but returned a %s. " + + "You may have forgotten to pass an argument to the type checker " + + "creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and " + + "shape all require an argument).", + componentName || "React class", + location, + typeSpecName, + typeof error$1 + ); - try { - return batchedUpdatesImpl(fn, a, b); - } finally { - isInsideEventHandler = false; - finishEventHandler(); - } -} // TODO: Replace with flushSync -function setBatchingImplementation( - _batchedUpdatesImpl, - _discreteUpdatesImpl, - _flushSyncImpl -) { - batchedUpdatesImpl = _batchedUpdatesImpl; - flushSyncImpl = _flushSyncImpl; -} + setCurrentlyValidatingElement(null); + } -function isInteractive(tag) { - return ( - tag === "button" || - tag === "input" || - tag === "select" || - tag === "textarea" - ); -} + if ( + error$1 instanceof Error && + !(error$1.message in loggedTypeFailures) + ) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error$1.message] = true; + setCurrentlyValidatingElement(element); -function shouldPreventMouseEvent(name, type, props) { - switch (name) { - case "onClick": - case "onClickCapture": - case "onDoubleClick": - case "onDoubleClickCapture": - case "onMouseDown": - case "onMouseDownCapture": - case "onMouseMove": - case "onMouseMoveCapture": - case "onMouseUp": - case "onMouseUpCapture": - case "onMouseEnter": - return !!(props.disabled && isInteractive(type)); + error("Failed %s type: %s", location, error$1.message); - default: - return false; + setCurrentlyValidatingElement(null); + } + } + } } } -/** - * @param {object} inst The instance, which is the source of events. - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @return {?function} The stored callback. - */ -function getListener(inst, registrationName) { - var stateNode = inst.stateNode; - - if (stateNode === null) { - // Work in progress (ex: onload events in incremental mode). - return null; - } +var warnedAboutMissingGetChildContext; - var props = getFiberCurrentPropsFromNode(stateNode); +{ + warnedAboutMissingGetChildContext = {}; +} - if (props === null) { - // Work in progress. - return null; - } +var emptyContextObject = {}; - var listener = props[registrationName]; +{ + Object.freeze(emptyContextObject); +} // A cursor to the current merged context object on the stack. - if (shouldPreventMouseEvent(registrationName, inst.type, props)) { - return null; - } +var contextStackCursor = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. - if (listener && typeof listener !== "function") { - throw new Error( - "Expected `" + - registrationName + - "` listener to be a function, instead got a value of `" + - typeof listener + - "` type." - ); - } +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. - return listener; -} +var previousContext = emptyContextObject; -var passiveBrowserEventsSupported = false; // Check if browser support events with passive listeners -// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support +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; + } -if (canUseDOM) { - try { - var options = {}; - Object.defineProperty(options, "passive", { - get: function () { - passiveBrowserEventsSupported = true; - } - }); - window.addEventListener("test", options, options); - window.removeEventListener("test", options, options); - } catch (e) { - passiveBrowserEventsSupported = false; + return contextStackCursor.current; } } -// Provided by www -var ReactFbErrorUtils = require("ReactFbErrorUtils"); - -if (typeof ReactFbErrorUtils.invokeGuardedCallback !== "function") { - throw new Error( - "Expected ReactFbErrorUtils.invokeGuardedCallback to be a function." - ); +function cacheContext(workInProgress, unmaskedContext, maskedContext) { + { + var instance = workInProgress.stateNode; + instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + instance.__reactInternalMemoizedMaskedChildContext = maskedContext; + } } -function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { - // This will call `this.onError(err)` if an error was caught. - ReactFbErrorUtils.invokeGuardedCallback.apply(this, arguments); -} +function getMaskedContext(workInProgress, unmaskedContext) { + { + var type = workInProgress.type; + var contextTypes = type.contextTypes; -var hasError = false; -var caughtError = null; // Used by event system to capture/rethrow the first error. + 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 hasRethrowError = false; -var rethrowError = null; -var reporter = { - onError: function (error) { - hasError = true; - caughtError = error; - } -}; -/** - * 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 - */ + var instance = workInProgress.stateNode; -function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { - hasError = false; - caughtError = null; - invokeGuardedCallbackImpl.apply(reporter, arguments); -} -/** - * 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 - */ + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) { + return instance.__reactInternalMemoizedMaskedChildContext; + } -function invokeGuardedCallbackAndCatchFirstError( - name, - func, - context, - a, - b, - c, - d, - e, - f -) { - invokeGuardedCallback.apply(this, arguments); + var context = {}; - if (hasError) { - var error = clearCaughtError(); + for (var key in contextTypes) { + context[key] = unmaskedContext[key]; + } - if (!hasRethrowError) { - hasRethrowError = true; - rethrowError = error; + { + var name = getComponentNameFromFiber(workInProgress) || "Unknown"; + checkPropTypes(contextTypes, context, "context", name); + } // Cache unmasked context so we can avoid recreating masked context unless necessary. + // Context is created before the class component is instantiated so check for instance. + + if (instance) { + cacheContext(workInProgress, unmaskedContext, context); } + + return context; } } -/** - * During execution of guarded functions we will capture the first error which - * we will rethrow to be handled by the top level error handler. - */ -function rethrowCaughtError() { - if (hasRethrowError) { - var error = rethrowError; - hasRethrowError = false; - rethrowError = null; - throw error; +function hasContextChanged() { + { + return didPerformWorkStackCursor.current; } } -function hasCaughtError() { - return hasError; -} -function clearCaughtError() { - if (hasError) { - var error = caughtError; - hasError = false; - caughtError = null; - return error; - } else { - throw new Error( - "clearCaughtError was called but no error was captured. This error " + - "is likely caused by a bug in React. Please file an issue." - ); + +function isContextProvider(type) { + { + var childContextTypes = type.childContextTypes; + return childContextTypes !== null && childContextTypes !== undefined; } } -var EventListenerWWW = require("EventListener"); - -function addEventBubbleListener(target, eventType, listener) { - return EventListenerWWW.listen(target, eventType, listener); -} -function addEventCaptureListener(target, eventType, listener) { - return EventListenerWWW.capture(target, eventType, listener); -} -function addEventCaptureListenerWithPassiveFlag( - target, - eventType, - listener, - passive -) { - return EventListenerWWW.captureWithPassiveFlag( - target, - eventType, - listener, - passive - ); -} -function addEventBubbleListenerWithPassiveFlag( - target, - eventType, - listener, - passive -) { - return EventListenerWWW.bubbleWithPassiveFlag( - target, - eventType, - listener, - passive - ); +function popContext(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } } -function removeEventListener(target, eventType, listener, capture) { - listener.remove(); -} // Flow magic to verify the exports of this file match the original version. -/** - * These variables store information about text content of a target node, - * allowing comparison of content before and after a given event. - * - * Identify the node where selection currently begins, then observe - * both its text content and its current position in the DOM. Since the - * browser may natively replace the target node during composition, we can - * use its position to find its replacement. - * - * - */ -var root = null; -var startText = null; -var fallbackText = null; -function initialize(nativeEventTarget) { - root = nativeEventTarget; - startText = getText(); - return true; -} -function reset() { - root = null; - startText = null; - fallbackText = null; +function popTopLevelContextObject(fiber) { + { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + } } -function getData() { - if (fallbackText) { - return fallbackText; + +function pushTopLevelContextObject(fiber, context, didChange) { + { + if (contextStackCursor.current !== emptyContextObject) { + throw new Error( + "Unexpected context found on stack. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } + + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); } +} - var start; - var startValue = startText; - var startLength = startValue.length; - var end; - var endValue = getText(); - var endLength = endValue.length; +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. - for (start = 0; start < startLength; start++) { - if (startValue[start] !== endValue[start]) { - break; + if (typeof instance.getChildContext !== "function") { + { + var componentName = getComponentNameFromFiber(fiber) || "Unknown"; + + if (!warnedAboutMissingGetChildContext[componentName]) { + warnedAboutMissingGetChildContext[componentName] = true; + + error( + "%s.childContextTypes is specified but there is no getChildContext() method " + + "on the instance. You can either define getChildContext() on %s or remove " + + "childContextTypes from it.", + componentName, + componentName + ); + } + } + + return parentContext; } - } - var minEnd = startLength - start; + var childContext = instance.getChildContext(); - for (end = 1; end <= minEnd; end++) { - if (startValue[startLength - end] !== endValue[endLength - end]) { - break; + for (var contextKey in childContext) { + if (!(contextKey in childContextTypes)) { + throw new Error( + (getComponentNameFromFiber(fiber) || "Unknown") + + '.getChildContext(): key "' + + contextKey + + '" is not defined in childContextTypes.' + ); + } } - } - var sliceTail = end > 1 ? 1 - end : undefined; - fallbackText = endValue.slice(start, sliceTail); - return fallbackText; -} -function getText() { - if ("value" in root) { - return root.value; - } + { + var name = getComponentNameFromFiber(fiber) || "Unknown"; + checkPropTypes(childContextTypes, childContext, "child context", name); + } - return root.textContent; + return assign({}, parentContext, childContext); + } } -/** - * `charCode` represents the actual "character code" and is safe to use with - * `String.fromCharCode`. As such, only keys that correspond to printable - * characters produce a valid `charCode`, the only exception to this is Enter. - * The Tab-key is considered non-printable and does not have a `charCode`, - * presumably because it does not produce a tab-character in browsers. - * - * @param {object} nativeEvent Native browser event. - * @return {number} Normalized `charCode` property. - */ -function getEventCharCode(nativeEvent) { - var charCode; - var keyCode = nativeEvent.keyCode; - - if ("charCode" in nativeEvent) { - charCode = nativeEvent.charCode; // FF does not set `charCode` for the Enter-key, check against `keyCode`. - - if (charCode === 0 && keyCode === 13) { - charCode = 13; - } - } else { - // IE8 does not implement `charCode`, but `keyCode` has the correct value. - charCode = keyCode; - } // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux) - // report Enter as charCode 10 when ctrl is pressed. +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. - if (charCode === 10) { - charCode = 13; - } // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. - // Must not discard the (non-)printable Enter-key. + 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. - if (charCode >= 32 || charCode === 13) { - return charCode; + previousContext = contextStackCursor.current; + push(contextStackCursor, memoizedMergedChildContext, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return true; } - - return 0; } -function functionThatReturnsTrue() { - return true; -} - -function functionThatReturnsFalse() { - return false; -} // This is intentionally a factory so that we have different returned constructors. -// If we had a single constructor, it would be megamorphic and engines would deopt. - -function createSyntheticEvent(Interface) { - /** - * Synthetic events are dispatched by event plugins, typically in response to a - * top-level event delegation handler. - * - * These systems should generally use pooling to reduce the frequency of garbage - * collection. The system should check `isPersistent` to determine whether the - * event should be released into the pool after being dispatched. Users that - * need a persisted event should invoke `persist`. - * - * Synthetic events (and subclasses) implement the DOM Level 3 Events API by - * normalizing browser quirks. Subclasses do not necessarily have to implement a - * DOM interface; custom application-specific events can also subclass this. - */ - // $FlowFixMe[missing-this-annot] - function SyntheticBaseEvent( - reactName, - reactEventType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - this._reactName = reactName; - this._targetInst = targetInst; - this.type = reactEventType; - this.nativeEvent = nativeEvent; - this.target = nativeEventTarget; - this.currentTarget = null; - - for (var propName in Interface) { - if (!Interface.hasOwnProperty(propName)) { - continue; - } - - var normalize = Interface[propName]; +function invalidateContextProvider(workInProgress, type, didChange) { + { + var instance = workInProgress.stateNode; - if (normalize) { - this[propName] = normalize(nativeEvent); - } else { - this[propName] = nativeEvent[propName]; - } + if (!instance) { + throw new Error( + "Expected to have an instance by this point. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } - var defaultPrevented = - nativeEvent.defaultPrevented != null - ? nativeEvent.defaultPrevented - : nativeEvent.returnValue === false; + 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. - if (defaultPrevented) { - this.isDefaultPrevented = functionThatReturnsTrue; + 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 { - this.isDefaultPrevented = functionThatReturnsFalse; + pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); } + } +} - this.isPropagationStopped = functionThatReturnsFalse; - return this; - } // $FlowFixMe[prop-missing] found when upgrading Flow +function findCurrentUnmaskedContext(fiber) { + { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + if (!isFiberMounted(fiber) || fiber.tag !== ClassComponent) { + throw new Error( + "Expected subtree parent to be a mounted class component. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } - assign(SyntheticBaseEvent.prototype, { - // $FlowFixMe[missing-this-annot] - preventDefault: function () { - this.defaultPrevented = true; - var event = this.nativeEvent; + var node = fiber; - if (!event) { - return; - } + do { + switch (node.tag) { + case HostRoot: + return node.stateNode.context; - if (event.preventDefault) { - event.preventDefault(); // $FlowFixMe - flow is not aware of `unknown` in IE - } else if (typeof event.returnValue !== "unknown") { - event.returnValue = false; - } + case ClassComponent: { + var Component = node.type; - this.isDefaultPrevented = functionThatReturnsTrue; - }, - // $FlowFixMe[missing-this-annot] - stopPropagation: function () { - var event = this.nativeEvent; + if (isContextProvider(Component)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } - if (!event) { - return; - } + break; + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - if (event.stopPropagation) { - event.stopPropagation(); // $FlowFixMe - flow is not aware of `unknown` in IE - } else if (typeof event.cancelBubble !== "unknown") { - // The ChangeEventPlugin registers a "propertychange" event for - // IE. This event does not support bubbling or cancelling, and - // any references to cancelBubble throw "Member not found". A - // typeof check of "unknown" circumvents this issue (and is also - // IE specific). - event.cancelBubble = true; - } + node = node.return; + } while (node !== null); - this.isPropagationStopped = functionThatReturnsTrue; - }, + throw new Error( + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } +} - /** - * We release all dispatched `SyntheticEvent`s after each event loop, adding - * them back into the pool. This allows a way to hold onto a reference that - * won't be added back into the pool. - */ - persist: function () { - // Modern event system doesn't use pooling. - }, +var LegacyRoot = 0; +var ConcurrentRoot = 1; - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: functionThatReturnsTrue - }); - return SyntheticBaseEvent; +// We use the existence of the state object as an indicator that the component +// is hidden. +var OffscreenVisible = + /* */ + 1; +var OffscreenDetached = + /* */ + 2; +var OffscreenPassiveEffectsConnected = + /* */ + 4; +function isOffscreenManual(offscreenFiber) { + return ( + offscreenFiber.memoizedProps !== null && + offscreenFiber.memoizedProps.mode === "manual" + ); } + /** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/ + * 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 EventInterface = { - eventPhase: 0, - bubbles: 0, - cancelable: 0, - timeStamp: function (event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: 0, - isTrusted: 0 -}; -var SyntheticEvent = createSyntheticEvent(EventInterface); - -var UIEventInterface = assign({}, EventInterface, { - view: 0, - detail: 0 -}); +var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] -var SyntheticUIEvent = createSyntheticEvent(UIEventInterface); -var lastMovementX; -var lastMovementY; -var lastMouseEvent; +var syncQueue = null; +var includesLegacySyncCallbacks = false; +var isFlushingSyncQueue = false; +function scheduleSyncCallback(callback) { + // Push this callback into an internal queue. We'll flush these either in + // the next tick, or earlier if something calls `flushSyncCallbackQueue`. + if (syncQueue === null) { + syncQueue = [callback]; + } else { + // Push onto existing queue. Don't need to schedule a callback because + // we already scheduled one when we created the queue. + syncQueue.push(callback); + } +} +function scheduleLegacySyncCallback(callback) { + includesLegacySyncCallbacks = true; + scheduleSyncCallback(callback); +} +function flushSyncCallbacksOnlyInLegacyMode() { + // Only flushes the queue if there's a legacy sync callback scheduled. + // TODO: There's only a single type of callback: performSyncOnWorkOnRoot. So + // it might make more sense for the queue to be a list of roots instead of a + // list of generic callbacks. Then we can have two: one for legacy roots, one + // for concurrent roots. And this method would only flush the legacy ones. + if (includesLegacySyncCallbacks) { + flushSyncCallbacks(); + } +} +function flushSyncCallbacks() { + if (!isFlushingSyncQueue && syncQueue !== null) { + // Prevent re-entrance. + isFlushingSyncQueue = true; // Set the event priority to discrete + // TODO: Is this necessary anymore? The only user code that runs in this + // queue is in the render or commit phases, which already set the + // event priority. Should be able to remove. -function updateMouseMovementPolyfillState(event) { - if (event !== lastMouseEvent) { - if (lastMouseEvent && event.type === "mousemove") { - // $FlowFixMe assuming this is a number - lastMovementX = event.screenX - lastMouseEvent.screenX; // $FlowFixMe assuming this is a number + var previousUpdatePriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var errors = null; + var queue = syncQueue; // $FlowFixMe[incompatible-use] found when upgrading Flow - lastMovementY = event.screenY - lastMouseEvent.screenY; - } else { - lastMovementX = 0; - lastMovementY = 0; - } + for (var i = 0; i < queue.length; i++) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + var callback = queue[i]; - lastMouseEvent = event; - } -} -/** - * @interface MouseEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ + try { + do { + var isSync = true; // $FlowFixMe[incompatible-type] we bail out when we get a null -var MouseEventInterface = assign({}, UIEventInterface, { - screenX: 0, - screenY: 0, - clientX: 0, - clientY: 0, - pageX: 0, - pageY: 0, - ctrlKey: 0, - shiftKey: 0, - altKey: 0, - metaKey: 0, - getModifierState: getEventModifierState, - button: 0, - buttons: 0, - relatedTarget: function (event) { - if (event.relatedTarget === undefined) - return event.fromElement === event.srcElement - ? event.toElement - : event.fromElement; - return event.relatedTarget; - }, - movementX: function (event) { - if ("movementX" in event) { - return event.movementX; + callback = callback(isSync); + } while (callback !== null); + } catch (error) { + // Collect errors so we can rethrow them at the end + if (errors === null) { + errors = [error]; + } else { + errors.push(error); + } + } } - updateMouseMovementPolyfillState(event); - return lastMovementX; - }, - movementY: function (event) { - if ("movementY" in event) { - return event.movementY; - } // Don't need to call updateMouseMovementPolyfillState() here - // because it's guaranteed to have already run when movementX - // was copied. + syncQueue = null; + includesLegacySyncCallbacks = false; + setCurrentUpdatePriority(previousUpdatePriority); + isFlushingSyncQueue = false; - return lastMovementY; + if (errors !== null) { + if (errors.length > 1) { + if (typeof AggregateError === "function") { + // eslint-disable-next-line no-undef + throw new AggregateError(errors); + } else { + for (var _i = 1; _i < errors.length; _i++) { + scheduleCallback$2( + ImmediatePriority, + throwError.bind(null, errors[_i]) + ); + } + + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; + } + } } -}); -var SyntheticMouseEvent = createSyntheticEvent(MouseEventInterface); -/** - * @interface DragEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ + return null; +} -var DragEventInterface = assign({}, MouseEventInterface, { - dataTransfer: 0 -}); +function throwError(error) { + throw error; +} -var SyntheticDragEvent = createSyntheticEvent(DragEventInterface); -/** - * @interface FocusEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ +var nativeConsole = console; +var nativeConsoleLog = null; +var pendingGroupArgs = []; +var printedGroupIndex = -1; -var FocusEventInterface = assign({}, UIEventInterface, { - relatedTarget: 0 -}); +function formatLanes(laneOrLanes) { + return "0b" + laneOrLanes.toString(2).padStart(31, "0"); +} -var SyntheticFocusEvent = createSyntheticEvent(FocusEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface - * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent - */ +function group() { + for ( + var _len = arguments.length, groupArgs = new Array(_len), _key = 0; + _key < _len; + _key++ + ) { + groupArgs[_key] = arguments[_key]; + } -var AnimationEventInterface = assign({}, EventInterface, { - animationName: 0, - elapsedTime: 0, - pseudoElement: 0 -}); + pendingGroupArgs.push(groupArgs); -var SyntheticAnimationEvent = createSyntheticEvent(AnimationEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/clipboard-apis/ - */ + if (nativeConsoleLog === null) { + nativeConsoleLog = nativeConsole.log; + nativeConsole.log = log; + } +} -var ClipboardEventInterface = assign({}, EventInterface, { - clipboardData: function (event) { - return "clipboardData" in event - ? event.clipboardData - : window.clipboardData; +function groupEnd() { + pendingGroupArgs.pop(); + + while (printedGroupIndex >= pendingGroupArgs.length) { + nativeConsole.groupEnd(); + printedGroupIndex--; } -}); -var SyntheticClipboardEvent = createSyntheticEvent(ClipboardEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents - */ + if (pendingGroupArgs.length === 0) { + nativeConsole.log = nativeConsoleLog; + nativeConsoleLog = null; + } +} -var CompositionEventInterface = assign({}, EventInterface, { - data: 0 -}); +function log() { + if (printedGroupIndex < pendingGroupArgs.length - 1) { + for (var i = printedGroupIndex + 1; i < pendingGroupArgs.length; i++) { + var groupArgs = pendingGroupArgs[i]; + nativeConsole.group.apply(nativeConsole, groupArgs); + } -var SyntheticCompositionEvent = createSyntheticEvent(CompositionEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 - * /#events-inputevents - */ -// Happens to share the same list for now. + printedGroupIndex = pendingGroupArgs.length - 1; + } -var SyntheticInputEvent = SyntheticCompositionEvent; -/** - * Normalization of deprecated HTML5 `key` values - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ + if (typeof nativeConsoleLog === "function") { + nativeConsoleLog.apply(void 0, arguments); + } else { + nativeConsole.log.apply(nativeConsole, arguments); + } +} -var normalizeKey = { - Esc: "Escape", - Spacebar: " ", - Left: "ArrowLeft", - Up: "ArrowUp", - Right: "ArrowRight", - Down: "ArrowDown", - Del: "Delete", - Win: "OS", - Menu: "ContextMenu", - Apps: "ContextMenu", - Scroll: "ScrollLock", - MozPrintableKey: "Unidentified" -}; -/** - * Translation from legacy `keyCode` to HTML5 `key` - * Only special keys supported, all others depend on keyboard layout or browser - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ - -var translateToKey = { - "8": "Backspace", - "9": "Tab", - "12": "Clear", - "13": "Enter", - "16": "Shift", - "17": "Control", - "18": "Alt", - "19": "Pause", - "20": "CapsLock", - "27": "Escape", - "32": " ", - "33": "PageUp", - "34": "PageDown", - "35": "End", - "36": "Home", - "37": "ArrowLeft", - "38": "ArrowUp", - "39": "ArrowRight", - "40": "ArrowDown", - "45": "Insert", - "46": "Delete", - "112": "F1", - "113": "F2", - "114": "F3", - "115": "F4", - "116": "F5", - "117": "F6", - "118": "F7", - "119": "F8", - "120": "F9", - "121": "F10", - "122": "F11", - "123": "F12", - "144": "NumLock", - "145": "ScrollLock", - "224": "Meta" -}; -/** - * @param {object} nativeEvent Native browser event. - * @return {string} Normalized `key` property. - */ - -function getEventKey(nativeEvent) { - if (nativeEvent.key) { - // Normalize inconsistent values reported by browsers due to - // implementations of a working draft specification. - // FireFox implements `key` but returns `MozPrintableKey` for all - // printable characters (normalized to `Unidentified`), ignore it. - var key = normalizeKey[nativeEvent.key] || nativeEvent.key; // $FlowFixMe unable to index with a `mixed` value - - if (key !== "Unidentified") { - return key; +var REACT_LOGO_STYLE = + "background-color: #20232a; color: #61dafb; padding: 0 2px;"; +function logCommitStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c commit%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" + ); } - } // Browser does not implement `key`, polyfill as much of it as we can. - - if (nativeEvent.type === "keypress") { - var charCode = getEventCharCode( - // $FlowFixMe unable to narrow to `KeyboardEvent` - nativeEvent - ); // The enter-key is technically both printable and non-printable and can - // thus be captured by `keypress`, no other non-printable key should. - - return charCode === 13 ? "Enter" : String.fromCharCode(charCode); } - - if (nativeEvent.type === "keydown" || nativeEvent.type === "keyup") { - // While user keyboard layout determines the actual meaning of each - // `keyCode` value, almost all function keys have a universal value. - // $FlowFixMe unable to index with a `mixed` value - return translateToKey[nativeEvent.keyCode] || "Unidentified"; +} +function logCommitStopped() { + { + if (enableDebugTracing) { + groupEnd(); + } } - - return ""; } -/** - * Translation from modifier key to the associated property in the event. - * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers - */ - -var modifierKeyToProp = { - Alt: "altKey", - Control: "ctrlKey", - Meta: "metaKey", - Shift: "shiftKey" -}; // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support -// getModifierState. If getModifierState is not supported, we map it to a set of -// modifier keys exposed by the event. In this case, Lock-keys are not supported. -// $FlowFixMe[missing-local-annot] -// $FlowFixMe[missing-this-annot] +var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; // $FlowFixMe: Flow cannot handle polymorphic WeakMaps -function modifierStateGetter(keyArg) { - var syntheticEvent = this; - var nativeEvent = syntheticEvent.nativeEvent; +var wakeableIDs = new PossiblyWeakMap$1(); +var wakeableID = 0; - if (nativeEvent.getModifierState) { - return nativeEvent.getModifierState(keyArg); +function getWakeableID(wakeable) { + if (!wakeableIDs.has(wakeable)) { + wakeableIDs.set(wakeable, wakeableID++); } - var keyProp = modifierKeyToProp[keyArg]; - return keyProp ? !!nativeEvent[keyProp] : false; + return wakeableIDs.get(wakeable); } -function getEventModifierState(nativeEvent) { - return modifierStateGetter; +function logComponentSuspended(componentName, wakeable) { + { + if (enableDebugTracing) { + var id = getWakeableID(wakeable); + var display = wakeable.displayName || wakeable; + log( + "%c\u269B\uFE0F%c " + componentName + " suspended", + REACT_LOGO_STYLE, + "color: #80366d; font-weight: bold;", + id, + display + ); + wakeable.then( + function () { + log( + "%c\u269B\uFE0F%c " + componentName + " resolved", + REACT_LOGO_STYLE, + "color: #80366d; font-weight: bold;", + id, + display + ); + }, + function () { + log( + "%c\u269B\uFE0F%c " + componentName + " rejected", + REACT_LOGO_STYLE, + "color: #80366d; font-weight: bold;", + id, + display + ); + } + ); + } + } } -/** - * @interface KeyboardEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ - -var KeyboardEventInterface = assign({}, UIEventInterface, { - key: getEventKey, - code: 0, - location: 0, - ctrlKey: 0, - shiftKey: 0, - altKey: 0, - metaKey: 0, - repeat: 0, - locale: 0, - getModifierState: getEventModifierState, - // Legacy Interface - charCode: function (event) { - // `charCode` is the result of a KeyPress event and represents the value of - // the actual printable character. - // KeyPress is deprecated, but its replacement is not yet final and not - // implemented in any major browser. Only KeyPress has charCode. - if (event.type === "keypress") { - return getEventCharCode( - // $FlowFixMe unable to narrow to `KeyboardEvent` - event +function logLayoutEffectsStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c layout effects%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" ); } - - return 0; - }, - keyCode: function (event) { - // `keyCode` is the result of a KeyDown/Up event and represents the value of - // physical keyboard key. - // The actual meaning of the value depends on the users' keyboard layout - // which cannot be detected. Assuming that it is a US keyboard layout - // provides a surprisingly accurate mapping for US and European users. - // Due to this, it is left to the user to implement at this time. - if (event.type === "keydown" || event.type === "keyup") { - return event.keyCode; + } +} +function logLayoutEffectsStopped() { + { + if (enableDebugTracing) { + groupEnd(); } - - return 0; - }, - which: function (event) { - // `which` is an alias for either `keyCode` or `charCode` depending on the - // type of the event. - if (event.type === "keypress") { - return getEventCharCode( - // $FlowFixMe unable to narrow to `KeyboardEvent` - event + } +} +function logPassiveEffectsStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c passive effects%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" ); } - - if (event.type === "keydown" || event.type === "keyup") { - return event.keyCode; + } +} +function logPassiveEffectsStopped() { + { + if (enableDebugTracing) { + groupEnd(); } - - return 0; } -}); +} +function logRenderStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c render%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" + ); + } + } +} +function logRenderStopped() { + { + if (enableDebugTracing) { + groupEnd(); + } + } +} +function logForceUpdateScheduled(componentName, lane) { + { + if (enableDebugTracing) { + log( + "%c\u269B\uFE0F%c " + + componentName + + " forced update %c(" + + formatLanes(lane) + + ")", + REACT_LOGO_STYLE, + "color: #db2e1f; font-weight: bold;", + "" + ); + } + } +} +function logStateUpdateScheduled(componentName, lane, payloadOrAction) { + { + if (enableDebugTracing) { + log( + "%c\u269B\uFE0F%c " + + componentName + + " updated state %c(" + + formatLanes(lane) + + ")", + REACT_LOGO_STYLE, + "color: #01a252; font-weight: bold;", + "", + payloadOrAction + ); + } + } +} -var SyntheticKeyboardEvent = createSyntheticEvent(KeyboardEventInterface); -/** - * @interface PointerEvent - * @see http://www.w3.org/TR/pointerevents/ - */ +// This is imported by the event replaying implementation in React DOM. It's +// in a separate file to break a circular dependency between the renderer and +// the reconciler. +function isRootDehydrated(root) { + var currentState = root.current.memoizedState; + return currentState.isDehydrated; +} -var PointerEventInterface = assign({}, MouseEventInterface, { - pointerId: 0, - width: 0, - height: 0, - pressure: 0, - tangentialPressure: 0, - tiltX: 0, - tiltY: 0, - twist: 0, - pointerType: 0, - isPrimary: 0 -}); +// Intentionally not using it yet to derisk the initial implementation, because +// the way we push/pop these values is a bit unusual. If there's a mistake, I'd +// rather the ids be wrong than crash the whole reconciler. -var SyntheticPointerEvent = createSyntheticEvent(PointerEventInterface); -/** - * @interface TouchEvent - * @see http://www.w3.org/TR/touch-events/ - */ +var forkStack = []; +var forkStackIndex = 0; +var treeForkProvider = null; +var treeForkCount = 0; +var idStack = []; +var idStackIndex = 0; +var treeContextProvider = null; +var treeContextId = 1; +var treeContextOverflow = ""; +function isForkedChild(workInProgress) { + warnIfNotHydrating(); + return (workInProgress.flags & Forked) !== NoFlags$1; +} +function getForksAtLevel(workInProgress) { + warnIfNotHydrating(); + return treeForkCount; +} +function getTreeId() { + var overflow = treeContextOverflow; + var idWithLeadingBit = treeContextId; + var id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit); + return id.toString(32) + overflow; +} +function pushTreeFork(workInProgress, totalChildren) { + // This is called right after we reconcile an array (or iterator) of child + // fibers, because that's the only place where we know how many children in + // the whole set without doing extra work later, or storing addtional + // information on the fiber. + // + // That's why this function is separate from pushTreeId — it's called during + // the render phase of the fork parent, not the child, which is where we push + // the other context values. + // + // In the Fizz implementation this is much simpler because the child is + // rendered in the same callstack as the parent. + // + // It might be better to just add a `forks` field to the Fiber type. It would + // make this module simpler. + warnIfNotHydrating(); + forkStack[forkStackIndex++] = treeForkCount; + forkStack[forkStackIndex++] = treeForkProvider; + treeForkProvider = workInProgress; + treeForkCount = totalChildren; +} +function pushTreeId(workInProgress, totalChildren, index) { + warnIfNotHydrating(); + idStack[idStackIndex++] = treeContextId; + idStack[idStackIndex++] = treeContextOverflow; + idStack[idStackIndex++] = treeContextProvider; + treeContextProvider = workInProgress; + var baseIdWithLeadingBit = treeContextId; + var baseOverflow = treeContextOverflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part + // of the id; we use it to account for leading 0s. -var TouchEventInterface = assign({}, UIEventInterface, { - touches: 0, - targetTouches: 0, - changedTouches: 0, - altKey: 0, - metaKey: 0, - ctrlKey: 0, - shiftKey: 0, - getModifierState: getEventModifierState -}); + var baseLength = getBitLength(baseIdWithLeadingBit) - 1; + var baseId = baseIdWithLeadingBit & ~(1 << baseLength); + var slot = index + 1; + var length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into + // consideration the leading 1 we use to mark the end of the sequence. -var SyntheticTouchEvent = createSyntheticEvent(TouchEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- - * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent - */ + if (length > 30) { + // We overflowed the bitwise-safe range. Fall back to slower algorithm. + // This branch assumes the length of the base id is greater than 5; it won't + // work for smaller ids, because you need 5 bits per character. + // + // We encode the id in multiple steps: first the base id, then the + // remaining digits. + // + // Each 5 bit sequence corresponds to a single base 32 character. So for + // example, if the current id is 23 bits long, we can convert 20 of those + // bits into a string of 4 characters, with 3 bits left over. + // + // First calculate how many bits in the base id represent a complete + // sequence of characters. + var numberOfOverflowBits = baseLength - (baseLength % 5); // Then create a bitmask that selects only those bits. -var TransitionEventInterface = assign({}, EventInterface, { - propertyName: 0, - elapsedTime: 0, - pseudoElement: 0 -}); + var newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string. -var SyntheticTransitionEvent = createSyntheticEvent(TransitionEventInterface); -/** - * @interface WheelEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ + var newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id. -var WheelEventInterface = assign({}, MouseEventInterface, { - deltaX: function (event) { - return "deltaX" in event - ? event.deltaX // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). - : "wheelDeltaX" in event // $FlowFixMe assuming this is a number - ? -event.wheelDeltaX - : 0; - }, - deltaY: function (event) { - return "deltaY" in event - ? event.deltaY // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). - : "wheelDeltaY" in event // $FlowFixMe assuming this is a number - ? -event.wheelDeltaY // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). - : "wheelDelta" in event // $FlowFixMe assuming this is a number - ? -event.wheelDelta - : 0; - }, - deltaZ: 0, - // Browsers without "deltaMode" is reporting in raw wheel delta where one - // notch on the scroll is always +/- 120, roughly equivalent to pixels. - // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or - // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. - deltaMode: 0 -}); + var restOfBaseId = baseId >> numberOfOverflowBits; + var restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because + // we made more room, this time it won't overflow. -var SyntheticWheelEvent = createSyntheticEvent(WheelEventInterface); + var restOfLength = getBitLength(totalChildren) + restOfBaseLength; + var restOfNewBits = slot << restOfBaseLength; + var id = restOfNewBits | restOfBaseId; + var overflow = newOverflow + baseOverflow; + treeContextId = (1 << restOfLength) | id; + treeContextOverflow = overflow; + } else { + // Normal path + var newBits = slot << baseLength; -var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space + var _id = newBits | baseId; -var START_KEYCODE = 229; -var canUseCompositionEvent = canUseDOM && "CompositionEvent" in window; -var documentMode = null; + var _overflow = baseOverflow; + treeContextId = (1 << length) | _id; + treeContextOverflow = _overflow; + } +} +function pushMaterializedTreeId(workInProgress) { + warnIfNotHydrating(); // This component materialized an id. This will affect any ids that appear + // in its children. -if (canUseDOM && "documentMode" in document) { - documentMode = document.documentMode; -} // Webkit offers a very useful `textInput` event that can be used to -// directly represent `beforeInput`. The IE `textinput` event is not as -// useful, so we don't use it. + var returnFiber = workInProgress.return; -var canUseTextInputEvent = canUseDOM && "TextEvent" in window && !documentMode; // In IE9+, we have access to composition events, but the data supplied -// by the native compositionend event may be incorrect. Japanese ideographic -// spaces, for instance (\u3000) are not recorded correctly. + if (returnFiber !== null) { + var numberOfForks = 1; + var slotIndex = 0; + pushTreeFork(workInProgress, numberOfForks); + pushTreeId(workInProgress, numberOfForks, slotIndex); + } +} -var useFallbackCompositionData = - canUseDOM && - (!canUseCompositionEvent || - (documentMode && documentMode > 8 && documentMode <= 11)); -var SPACEBAR_CODE = 32; -var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); +function getBitLength(number) { + return 32 - clz32(number); +} -function registerEvents$3() { - registerTwoPhaseEvent("onBeforeInput", [ - "compositionend", - "keypress", - "textInput", - "paste" - ]); - registerTwoPhaseEvent("onCompositionEnd", [ - "compositionend", - "focusout", - "keydown", - "keypress", - "keyup", - "mousedown" - ]); - registerTwoPhaseEvent("onCompositionStart", [ - "compositionstart", - "focusout", - "keydown", - "keypress", - "keyup", - "mousedown" - ]); - registerTwoPhaseEvent("onCompositionUpdate", [ - "compositionupdate", - "focusout", - "keydown", - "keypress", - "keyup", - "mousedown" - ]); -} // Track whether we've ever handled a keypress on the space key. - -var hasSpaceKeypress = false; -/** - * Return whether a native keypress event is assumed to be a command. - * This is required because Firefox fires `keypress` events for key commands - * (cut, copy, select-all, etc.) even though no character is inserted. - */ - -function isKeypressCommand(nativeEvent) { - return ( - (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && // ctrlKey && altKey is equivalent to AltGr, and is not a command. - !(nativeEvent.ctrlKey && nativeEvent.altKey) - ); +function getLeadingBit(id) { + return 1 << (getBitLength(id) - 1); } -/** - * Translate native top level events into event types. - */ -function getCompositionEventType(domEventName) { - switch (domEventName) { - case "compositionstart": - return "onCompositionStart"; +function popTreeContext(workInProgress) { + // Restore the previous values. + // This is a bit more complicated than other context-like modules in Fiber + // because the same Fiber may appear on the stack multiple times and for + // different reasons. We have to keep popping until the work-in-progress is + // no longer at the top of the stack. + while (workInProgress === treeForkProvider) { + treeForkProvider = forkStack[--forkStackIndex]; + forkStack[forkStackIndex] = null; + treeForkCount = forkStack[--forkStackIndex]; + forkStack[forkStackIndex] = null; + } - case "compositionend": - return "onCompositionEnd"; + while (workInProgress === treeContextProvider) { + treeContextProvider = idStack[--idStackIndex]; + idStack[idStackIndex] = null; + treeContextOverflow = idStack[--idStackIndex]; + idStack[idStackIndex] = null; + treeContextId = idStack[--idStackIndex]; + idStack[idStackIndex] = null; + } +} +function getSuspendedTreeContext() { + warnIfNotHydrating(); - case "compositionupdate": - return "onCompositionUpdate"; + if (treeContextProvider !== null) { + return { + id: treeContextId, + overflow: treeContextOverflow + }; + } else { + return null; } } -/** - * Does our fallback best-guess model think this event signifies that - * composition has begun? - */ +function restoreSuspendedTreeContext(workInProgress, suspendedContext) { + warnIfNotHydrating(); + idStack[idStackIndex++] = treeContextId; + idStack[idStackIndex++] = treeContextOverflow; + idStack[idStackIndex++] = treeContextProvider; + treeContextId = suspendedContext.id; + treeContextOverflow = suspendedContext.overflow; + treeContextProvider = workInProgress; +} -function isFallbackCompositionStart(domEventName, nativeEvent) { - return domEventName === "keydown" && nativeEvent.keyCode === START_KEYCODE; +function warnIfNotHydrating() { + { + if (!getIsHydrating()) { + error( + "Expected to be hydrating. This is a bug in React. Please file " + + "an issue." + ); + } + } } -/** - * Does our fallback mode think that this event is the end of composition? - */ -function isFallbackCompositionEnd(domEventName, nativeEvent) { - switch (domEventName) { - case "keyup": - // Command keys insert or clear IME input. - return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; +// This may have been an insertion or a hydration. - case "keydown": - // Expect IME keyCode on each keydown. If we get any other - // code we must have exited earlier. - return nativeEvent.keyCode !== START_KEYCODE; +var hydrationParentFiber = null; +var nextHydratableInstance = null; +var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches +// due to earlier mismatches or a suspended fiber. - case "keypress": - case "mousedown": - case "focusout": - // Events are not possible without cancelling IME. - return true; +var didSuspendOrErrorDEV = false; // Hydration errors that were thrown inside this boundary - default: - return false; +var hydrationErrors = null; +var rootOrSingletonContext = false; + +function warnIfHydrating() { + { + if (isHydrating) { + error( + "We should not be hydrating here. This is a bug in React. Please file a bug." + ); + } } } -/** - * Google Input Tools provides composition data via a CustomEvent, - * with the `data` property populated in the `detail` object. If this - * is available on the event object, use it. If not, this is a plain - * composition event and we have nothing special to extract. - * - * @param {object} nativeEvent - * @return {?string} - */ - -function getDataFromCustomEvent(nativeEvent) { - var detail = nativeEvent.detail; - if (typeof detail === "object" && "data" in detail) { - return detail.data; +function markDidThrowWhileHydratingDEV() { + { + didSuspendOrErrorDEV = true; + } +} +function didSuspendOrErrorWhileHydratingDEV() { + { + return didSuspendOrErrorDEV; } - - return null; } -/** - * Check if a composition event was triggered by Korean IME. - * Our fallback mode does not work well with IE's Korean IME, - * so just use native composition events when Korean IME is used. - * Although CompositionEvent.locale property is deprecated, - * it is available in IE, where our fallback mode is enabled. - * - * @param {object} nativeEvent - * @return {boolean} - */ - -function isUsingKoreanIME(nativeEvent) { - return nativeEvent.locale === "ko"; -} // Track the current IME composition status, if any. -var isComposing = false; -/** - * @return {?object} A SyntheticCompositionEvent. - */ +function enterHydrationState(fiber) { + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = + getFirstHydratableChildWithinContainer(parentInstance); + hydrationParentFiber = fiber; + isHydrating = true; + hydrationErrors = null; + didSuspendOrErrorDEV = false; + rootOrSingletonContext = true; + return true; +} -function extractCompositionEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget +function reenterHydrationStateFromDehydratedSuspenseInstance( + fiber, + suspenseInstance, + treeContext ) { - var eventType; - var fallbackData; + nextHydratableInstance = + getFirstHydratableChildWithinSuspenseInstance(suspenseInstance); + hydrationParentFiber = fiber; + isHydrating = true; + hydrationErrors = null; + didSuspendOrErrorDEV = false; + rootOrSingletonContext = false; - if (canUseCompositionEvent) { - eventType = getCompositionEventType(domEventName); - } else if (!isComposing) { - if (isFallbackCompositionStart(domEventName, nativeEvent)) { - eventType = "onCompositionStart"; - } - } else if (isFallbackCompositionEnd(domEventName, nativeEvent)) { - eventType = "onCompositionEnd"; + if (treeContext !== null) { + restoreSuspendedTreeContext(fiber, treeContext); } - if (!eventType) { - return null; - } + return true; +} - if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { - // The current composition is stored statically and must not be - // overwritten while composition continues. - if (!isComposing && eventType === "onCompositionStart") { - isComposing = initialize(nativeEventTarget); - } else if (eventType === "onCompositionEnd") { - if (isComposing) { - fallbackData = getData(); +function warnUnhydratedInstance(returnFiber, instance) { + { + switch (returnFiber.tag) { + case HostRoot: { + didNotHydrateInstanceWithinContainer( + returnFiber.stateNode.containerInfo, + instance + ); + break; } - } - } - - var listeners = accumulateTwoPhaseListeners(targetInst, eventType); - - if (listeners.length > 0) { - var event = new SyntheticCompositionEvent( - eventType, - domEventName, - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); - if (fallbackData) { - // Inject data generated from fallback path into the synthetic event. - // This matches the property of native CompositionEventInterface. - // $FlowFixMe[incompatible-use] - event.data = fallbackData; - } else { - var customData = getDataFromCustomEvent(nativeEvent); + case HostSingleton: + case HostComponent: { + var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode; + didNotHydrateInstance( + returnFiber.type, + returnFiber.memoizedProps, + returnFiber.stateNode, + instance, // TODO: Delete this argument when we remove the legacy root API. + isConcurrentMode + ); + break; + } - if (customData !== null) { - // $FlowFixMe[incompatible-use] - event.data = customData; + case SuspenseComponent: { + var suspenseState = returnFiber.memoizedState; + if (suspenseState.dehydrated !== null) + didNotHydrateInstanceWithinSuspenseInstance( + suspenseState.dehydrated, + instance + ); + break; } } } } -function getNativeBeforeInputChars(domEventName, nativeEvent) { - switch (domEventName) { - case "compositionend": - return getDataFromCustomEvent(nativeEvent); +function deleteHydratableInstance(returnFiber, instance) { + warnUnhydratedInstance(returnFiber, instance); + var childToDelete = createFiberFromHostInstanceForDeletion(); + childToDelete.stateNode = instance; + childToDelete.return = returnFiber; + var deletions = returnFiber.deletions; - case "keypress": - /** - * If native `textInput` events are available, our goal is to make - * use of them. However, there is a special case: the spacebar key. - * In Webkit, preventing default on a spacebar `textInput` event - * cancels character insertion, but it *also* causes the browser - * to fall back to its default spacebar behavior of scrolling the - * page. - * - * Tracking at: - * https://code.google.com/p/chromium/issues/detail?id=355103 - * - * To avoid this issue, use the keypress event as if no `textInput` - * event is available. - */ - var which = nativeEvent.which; + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } +} - if (which !== SPACEBAR_CODE) { - return null; - } +function warnNonhydratedInstance(returnFiber, fiber) { + { + if (didSuspendOrErrorDEV) { + // Inside a boundary that already suspended. We're currently rendering the + // siblings of a suspended node. The mismatch may be due to the missing + // data, so it's probably a false positive. + return; + } - hasSpaceKeypress = true; - return SPACEBAR_CHAR; + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; - case "textInput": - // Record the characters to be added to the DOM. - var chars = nativeEvent.data; // If it's a spacebar character, assume that we have already handled - // it at the keypress level and bail immediately. Android Chrome - // doesn't give us keycodes, so we need to ignore it. + switch (fiber.tag) { + case HostSingleton: + case HostComponent: + var type = fiber.type; + didNotFindHydratableInstanceWithinContainer(parentContainer, type); + break; - if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { - return null; - } + case HostText: + var text = fiber.pendingProps; + didNotFindHydratableTextInstanceWithinContainer( + parentContainer, + text + ); + break; + } - return chars; + break; + } - default: - // For other native event types, do nothing. - return null; - } -} -/** - * For browsers that do not provide the `textInput` event, extract the - * appropriate string to use for SyntheticInputEvent. - */ + case HostSingleton: + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; -function getFallbackBeforeInputChars(domEventName, nativeEvent) { - // If we are currently composing (IME) and using a fallback to do so, - // try to extract the composed characters from the fallback object. - // If composition event is available, we extract a string only at - // compositionevent, otherwise extract it at fallback events. - if (isComposing) { - if ( - domEventName === "compositionend" || - (!canUseCompositionEvent && - isFallbackCompositionEnd(domEventName, nativeEvent)) - ) { - var chars = getData(); - reset(); - isComposing = false; - return chars; - } + switch (fiber.tag) { + case HostSingleton: + case HostComponent: { + var _type = fiber.type; + var _props = fiber.pendingProps; + var isConcurrentMode = + (returnFiber.mode & ConcurrentMode) !== NoMode; + didNotFindHydratableInstance( + parentType, + parentProps, + parentInstance, + _type, + _props, // TODO: Delete this argument when we remove the legacy root API. + isConcurrentMode + ); + break; + } - return null; - } + case HostText: { + var _text = fiber.pendingProps; - switch (domEventName) { - case "paste": - // If a paste event occurs after a keypress, throw out the input - // chars. Paste events should not lead to BeforeInput events. - return null; + var _isConcurrentMode = + (returnFiber.mode & ConcurrentMode) !== NoMode; - case "keypress": - /** - * As of v27, Firefox may fire keypress events even when no character - * will be inserted. A few possibilities: - * - * - `which` is `0`. Arrow keys, Esc key, etc. - * - * - `which` is the pressed key code, but no char is available. - * Ex: 'AltGr + d` in Polish. There is no modified character for - * this key combination and no character is inserted into the - * document, but FF fires the keypress for char code `100` anyway. - * No `input` event will occur. - * - * - `which` is the pressed key code, but a command combination is - * being used. Ex: `Cmd+C`. No character is inserted, and no - * `input` event will occur. - */ - if (!isKeypressCommand(nativeEvent)) { - // IE fires the `keypress` event when a user types an emoji via - // Touch keyboard of Windows. In such a case, the `char` property - // holds an emoji character like `\uD83D\uDE0A`. Because its length - // is 2, the property `which` does not represent an emoji correctly. - // In such a case, we directly return the `char` property instead of - // using `which`. - if (nativeEvent.char && nativeEvent.char.length > 1) { - return nativeEvent.char; - } else if (nativeEvent.which) { - return String.fromCharCode(nativeEvent.which); + didNotFindHydratableTextInstance( + parentType, + parentProps, + parentInstance, + _text, // TODO: Delete this argument when we remove the legacy root API. + _isConcurrentMode + ); + break; + } } + + break; } - return null; + case SuspenseComponent: { + var suspenseState = returnFiber.memoizedState; + var _parentInstance = suspenseState.dehydrated; + if (_parentInstance !== null) + switch (fiber.tag) { + case HostSingleton: + case HostComponent: + var _type2 = fiber.type; + didNotFindHydratableInstanceWithinSuspenseInstance( + _parentInstance, + _type2 + ); + break; - case "compositionend": - return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) - ? null - : nativeEvent.data; + case HostText: + var _text2 = fiber.pendingProps; + didNotFindHydratableTextInstanceWithinSuspenseInstance( + _parentInstance, + _text2 + ); + break; + } + break; + } - default: - return null; + default: + return; + } } } -/** - * Extract a SyntheticInputEvent for `beforeInput`, based on either native - * `textInput` or fallback behavior. - * - * @return {?object} A SyntheticInputEvent. - */ -function extractBeforeInputEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget -) { - var chars; - - if (canUseTextInputEvent) { - chars = getNativeBeforeInputChars(domEventName, nativeEvent); - } else { - chars = getFallbackBeforeInputChars(domEventName, nativeEvent); - } // If no characters are being inserted, no BeforeInput event should - // be fired. - - if (!chars) { - return null; - } - - var listeners = accumulateTwoPhaseListeners(targetInst, "onBeforeInput"); +function insertNonHydratedInstance(returnFiber, fiber) { + fiber.flags = (fiber.flags & ~Hydrating) | Placement; + warnNonhydratedInstance(returnFiber, fiber); +} - if (listeners.length > 0) { - var event = new SyntheticInputEvent( - "onBeforeInput", - "beforeinput", - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); // $FlowFixMe[incompatible-use] +function tryHydrateInstance(fiber, nextInstance) { + // fiber is a HostComponent Fiber + var instance = canHydrateInstance(nextInstance, fiber.type); - event.data = chars; + if (instance !== null) { + fiber.stateNode = instance; + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(instance); + rootOrSingletonContext = false; + return true; } -} -/** - * Create an `onBeforeInput` event to match - * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. - * - * This event plugin is based on the native `textInput` event - * available in Chrome, Safari, Opera, and IE. This event fires after - * `onKeyPress` and `onCompositionEnd`, but before `onInput`. - * - * `beforeInput` is spec'd but not implemented in any browsers, and - * the `input` event does not provide any useful information about what has - * actually been added, contrary to the spec. Thus, `textInput` is the best - * available event to identify the characters that have actually been inserted - * into the target node. - * - * This plugin is also responsible for emitting `composition` events, thus - * allowing us to share composition fallback code for both `beforeInput` and - * `composition` event types. - */ -function extractEvents$5( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - extractCompositionEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractBeforeInputEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); + return false; } -/** - * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary - */ -var supportedInputTypes = { - color: true, - date: true, - datetime: true, - "datetime-local": true, - email: true, - month: true, - number: true, - password: true, - range: true, - search: true, - tel: true, - text: true, - time: true, - url: true, - week: true -}; - -function isTextInputElement(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); +function tryHydrateText(fiber, nextInstance) { + // fiber is a HostText Fiber + var text = fiber.pendingProps; + var textInstance = canHydrateTextInstance(nextInstance, text); - if (nodeName === "input") { - return !!supportedInputTypes[elem.type]; - } + if (textInstance !== null) { + fiber.stateNode = textInstance; + hydrationParentFiber = fiber; // Text Instances don't have children so there's nothing to hydrate. - if (nodeName === "textarea") { + nextHydratableInstance = null; return true; } return false; } -/** - * Checks if an event is supported in the current execution environment. - * - * NOTE: This will not work correctly for non-generic events such as `change`, - * `reset`, `load`, `error`, and `select`. - * - * Borrows from Modernizr. - * - * @param {string} eventNameSuffix Event name, e.g. "click". - * @return {boolean} True if the event is supported. - * @internal - * @license Modernizr 3.0.0pre (Custom Build) | MIT - */ +function tryHydrateSuspense(fiber, nextInstance) { + // fiber is a SuspenseComponent Fiber + var suspenseInstance = canHydrateSuspenseInstance(nextInstance); -function isEventSupported(eventNameSuffix) { - if (!canUseDOM) { - return false; - } + if (suspenseInstance !== null) { + var suspenseState = { + dehydrated: suspenseInstance, + treeContext: getSuspendedTreeContext(), + retryLane: OffscreenLane + }; + fiber.memoizedState = suspenseState; // Store the dehydrated fragment as a child fiber. + // This simplifies the code for getHostSibling and deleting nodes, + // since it doesn't have to consider all Suspense boundaries and + // check if they're dehydrated ones or not. - var eventName = "on" + eventNameSuffix; - var isSupported = eventName in document; + var dehydratedFragment = + createFiberFromDehydratedFragment(suspenseInstance); + dehydratedFragment.return = fiber; + fiber.child = dehydratedFragment; + hydrationParentFiber = fiber; // While a Suspense Instance does have children, we won't step into + // it during the first pass. Instead, we'll reenter it later. - if (!isSupported) { - var element = document.createElement("div"); - element.setAttribute(eventName, "return;"); - isSupported = typeof element[eventName] === "function"; + nextHydratableInstance = null; + return true; } - return isSupported; -} - -function registerEvents$2() { - registerTwoPhaseEvent("onChange", [ - "change", - "click", - "focusin", - "focusout", - "input", - "keydown", - "keyup", - "selectionchange" - ]); + return false; } -function createAndAccumulateChangeEvent( - dispatchQueue, - inst, - nativeEvent, - target -) { - // Flag this event loop as needing state restore. - enqueueStateRestore(target); - var listeners = accumulateTwoPhaseListeners(inst, "onChange"); - - if (listeners.length > 0) { - var event = new SyntheticEvent( - "onChange", - "change", - null, - nativeEvent, - target - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); - } +function shouldClientRenderOnMismatch(fiber) { + return ( + (fiber.mode & ConcurrentMode) !== NoMode && + (fiber.flags & DidCapture) === NoFlags$1 + ); } -/** - * For IE shims - */ - -var activeElement$1 = null; -var activeElementInst$1 = null; -/** - * SECTION: handle `change` event - */ -function shouldUseChangeEvent(elem) { - var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); - return ( - nodeName === "select" || (nodeName === "input" && elem.type === "file") +function throwOnHydrationMismatch(fiber) { + throw new Error( + "Hydration failed because the initial UI does not match what was " + + "rendered on the server." ); } -function manualDispatchChangeEvent(nativeEvent) { - var dispatchQueue = []; - createAndAccumulateChangeEvent( - dispatchQueue, - activeElementInst$1, - nativeEvent, - getEventTarget(nativeEvent) - ); // If change and propertychange bubbled, we'd just bind to it like all the - // other events and have it go through ReactBrowserEventEmitter. Since it - // doesn't, we manually listen for the events and so we have to enqueue and - // process the abstract event manually. - // - // Batching is necessary here in order to ensure that all event handlers run - // before the next rerender (including event handlers attached to ancestor - // elements instead of directly on the input). Without this, controlled - // components don't work properly in conjunction with event bubbling because - // the component is rerendered and the value reverted before all the event - // handlers can run. See https://github.com/facebook/react/issues/708. +function claimHydratableSingleton(fiber) { + { + if (!isHydrating) { + return; + } - batchedUpdates$1(runEventInBatch, dispatchQueue); + var currentRootContainer = getRootHostContainer(); + var currentHostContext = getHostContext(); + var instance = (fiber.stateNode = resolveSingletonInstance( + fiber.type, + fiber.pendingProps, + currentRootContainer, + currentHostContext, + false + )); + hydrationParentFiber = fiber; + rootOrSingletonContext = true; + nextHydratableInstance = getFirstHydratableChild(instance); + } } -function runEventInBatch(dispatchQueue) { - processDispatchQueue(dispatchQueue, 0); +function advanceToFirstAttemptableInstance(fiber) { + // fiber is HostComponent Fiber + while ( + nextHydratableInstance && + shouldSkipHydratableForInstance( + nextHydratableInstance, + fiber.type, + fiber.pendingProps + ) + ) { + // Flow doesn't understand that inside this block nextHydratableInstance is not null + var instance = nextHydratableInstance; + nextHydratableInstance = getNextHydratableSibling(instance); + } } -function getInstIfValueChanged(targetInst) { - var targetNode = getNodeFromInstance(targetInst); - - if (updateValueIfChanged(targetNode)) { - return targetInst; +function advanceToFirstAttemptableTextInstance() { + while ( + nextHydratableInstance && + shouldSkipHydratableForTextInstance(nextHydratableInstance) + ) { + // Flow doesn't understand that inside this block nextHydratableInstance is not null + var instance = nextHydratableInstance; + nextHydratableInstance = getNextHydratableSibling(instance); } } -function getTargetInstForChangeEvent(domEventName, targetInst) { - if (domEventName === "change") { - return targetInst; +function advanceToFirstAttemptableSuspenseInstance() { + while ( + nextHydratableInstance && + shouldSkipHydratableForSuspenseInstance(nextHydratableInstance) + ) { + // Flow doesn't understand that inside this block nextHydratableInstance is not null + var instance = nextHydratableInstance; + nextHydratableInstance = getNextHydratableSibling(instance); } } -/** - * SECTION: handle `input` event - */ -var isInputEventSupported = false; +function tryToClaimNextHydratableInstance(fiber) { + if (!isHydrating) { + return; + } -if (canUseDOM) { - // IE9 claims to support the input event but fails to trigger it when - // deleting text, so we ignore its input events. - isInputEventSupported = - isEventSupported("input") && - (!document.documentMode || document.documentMode > 9); -} -/** - * (For IE <=9) Starts tracking propertychange events on the passed-in element - * and override the value property so that we can distinguish user events from - * value changes in JS. - */ + { + if (!isHydratableType(fiber.type, fiber.pendingProps)) { + // This fiber never hydrates from the DOM and always does an insert + fiber.flags = (fiber.flags & ~Hydrating) | Placement; + isHydrating = false; + hydrationParentFiber = fiber; + return; + } + } -function startWatchingForValueChange(target, targetInst) { - activeElement$1 = target; - activeElementInst$1 = targetInst; - activeElement$1.attachEvent("onpropertychange", handlePropertyChange); -} -/** - * (For IE <=9) Removes the event listeners from the currently-tracked element, - * if any exists. - */ + var initialInstance = nextHydratableInstance; -function stopWatchingForValueChange() { - if (!activeElement$1) { - return; + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableInstance(fiber); } - activeElement$1.detachEvent("onpropertychange", handlePropertyChange); - activeElement$1 = null; - activeElementInst$1 = null; -} -/** - * (For IE <=9) Handles a propertychange event, sending a `change` event if - * the value of the active element has changed. - */ -// $FlowFixMe[missing-local-annot] + var nextInstance = nextHydratableInstance; -function handlePropertyChange(nativeEvent) { - if (nativeEvent.propertyName !== "value") { + if (!nextInstance) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // Nothing to hydrate. Make it an insertion. + + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; return; } - if (getInstIfValueChanged(activeElementInst$1)) { - manualDispatchChangeEvent(nativeEvent); - } -} + var firstAttemptedInstance = nextInstance; -function handleEventsForInputEventPolyfill(domEventName, target, targetInst) { - if (domEventName === "focusin") { - // In IE9, propertychange fires for most input events but is buggy and - // doesn't fire when text is deleted, but conveniently, selectionchange - // appears to fire in all of the remaining cases so we catch those and - // forward the event if the value has changed - // In either case, we don't want to call the event handler if the value - // is changed from JS so we redefine a setter for `.value` that updates - // our activeElementValue variable, allowing us to ignore those changes - // - // stopWatching() should be a noop here but we call it just in case we - // missed a blur event somehow. - stopWatchingForValueChange(); - startWatchingForValueChange(target, targetInst); - } else if (domEventName === "focusout") { - stopWatchingForValueChange(); - } -} // For IE8 and IE9. + if (!tryHydrateInstance(fiber, nextInstance)) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // 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. -function getTargetInstForInputEventPolyfill(domEventName, targetInst) { - if ( - domEventName === "selectionchange" || - domEventName === "keyup" || - domEventName === "keydown" - ) { - // On the selectionchange event, the target is just document which isn't - // helpful for us so just check activeElement instead. - // - // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire - // propertychange on the first input event after setting `value` from a - // script and fires only keydown, keypress, keyup. Catching keyup usually - // gets it and catching keydown lets us fire an event for the first - // keystroke if user does a key repeat (it'll be a little delayed: right - // before the second keystroke). Other input methods (e.g., paste) seem to - // fire selectionchange normally. - return getInstIfValueChanged(activeElementInst$1); - } -} -/** - * SECTION: handle `click` event - */ + nextHydratableInstance = getNextHydratableSibling(nextInstance); + var prevHydrationParentFiber = hydrationParentFiber; -function shouldUseClickEvent(elem) { - // Use the `click` event to detect changes to checkbox and radio inputs. - // This approach works across all browsers, whereas `change` does not fire - // until `blur` in IE8. - var nodeName = elem.nodeName; - return ( - nodeName && - nodeName.toLowerCase() === "input" && - (elem.type === "checkbox" || elem.type === "radio") - ); -} + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableInstance(fiber); + } -function getTargetInstForClickEvent(domEventName, targetInst) { - if (domEventName === "click") { - return getInstIfValueChanged(targetInst); - } -} + if ( + !nextHydratableInstance || + !tryHydrateInstance(fiber, nextHydratableInstance) + ) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + 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. -function getTargetInstForInputOrChangeEvent(domEventName, targetInst) { - if (domEventName === "input" || domEventName === "change") { - return getInstIfValueChanged(targetInst); + deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); } } -function handleControlledInputBlur(node) { - var state = node._wrapperState; - - if (!state || !state.controlled || node.type !== "number") { +function tryToClaimNextHydratableTextInstance(fiber) { + if (!isHydrating) { return; } - if (!disableInputAttributeSyncing) { - // If controlled, assign the value attribute to the current value on blur - setDefaultValue(node, "number", node.value); + var text = fiber.pendingProps; + var isHydratable = isHydratableText(text); + var initialInstance = nextHydratableInstance; + + if (rootOrSingletonContext && isHydratable) { + // We may need to skip past certain nodes in these contexts. + // We don't skip if the text is not hydratable because we know no hydratables + // exist which could match this Fiber + advanceToFirstAttemptableTextInstance(); } -} -/** - * This plugin creates an `onChange` event that normalizes change events - * across form elements. This event fires at a time when it's possible to - * change the element's value without seeing a flicker. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - select - */ -function extractEvents$4( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var targetNode = targetInst ? getNodeFromInstance(targetInst) : window; - var getTargetInstFunc, handleEventFunc; + var nextInstance = nextHydratableInstance; - if (shouldUseChangeEvent(targetNode)) { - getTargetInstFunc = getTargetInstForChangeEvent; - } else if (isTextInputElement(targetNode)) { - if (isInputEventSupported) { - getTargetInstFunc = getTargetInstForInputOrChangeEvent; - } else { - getTargetInstFunc = getTargetInstForInputEventPolyfill; - handleEventFunc = handleEventsForInputEventPolyfill; - } - } else if (shouldUseClickEvent(targetNode)) { - getTargetInstFunc = getTargetInstForClickEvent; - } else if ( - enableCustomElementPropertySupport && - targetInst && - isCustomComponent(targetInst.elementType, targetInst.memoizedProps) - ) { - getTargetInstFunc = getTargetInstForChangeEvent; + if (!nextInstance || !isHydratable) { + // We exclude non hydrabable text because we know there are no matching hydratables. + // We either throw or insert depending on the render mode. + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // Nothing to hydrate. Make it an insertion. + + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + return; } - if (getTargetInstFunc) { - var inst = getTargetInstFunc(domEventName, targetInst); + var firstAttemptedInstance = nextInstance; - if (inst) { - createAndAccumulateChangeEvent( - dispatchQueue, - inst, - nativeEvent, - nativeEventTarget - ); - return; + if (!tryHydrateText(fiber, nextInstance)) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // 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. + + nextHydratableInstance = getNextHydratableSibling(nextInstance); + var prevHydrationParentFiber = hydrationParentFiber; + + if (rootOrSingletonContext && isHydratable) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableTextInstance(); } - } - if (handleEventFunc) { - handleEventFunc(domEventName, targetNode, targetInst); - } // When blurring, set the value attribute for number inputs + if ( + !nextHydratableInstance || + !tryHydrateText(fiber, nextHydratableInstance) + ) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + 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. - if (domEventName === "focusout") { - handleControlledInputBlur(targetNode); + deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); } } -function registerEvents$1() { - registerDirectEvent("onMouseEnter", ["mouseout", "mouseover"]); - registerDirectEvent("onMouseLeave", ["mouseout", "mouseover"]); - registerDirectEvent("onPointerEnter", ["pointerout", "pointerover"]); - registerDirectEvent("onPointerLeave", ["pointerout", "pointerover"]); -} -/** - * For almost every interaction we care about, there will be both a top-level - * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that - * we do not extract duplicate events. However, moving the mouse into the - * browser from outside will not fire a `mouseout` event. In this case, we use - * the `mouseover` top-level event. - */ - -function extractEvents$3( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var isOverEvent = - domEventName === "mouseover" || domEventName === "pointerover"; - var isOutEvent = domEventName === "mouseout" || domEventName === "pointerout"; +function tryToClaimNextHydratableSuspenseInstance(fiber) { + if (!isHydrating) { + return; + } - if (isOverEvent && !isReplayingEvent(nativeEvent)) { - // If this is an over event with a target, we might have already dispatched - // the event in the out event of the other target. If this is replayed, - // then it's because we couldn't dispatch against this target previously - // so we have to do it now instead. - var related = nativeEvent.relatedTarget || nativeEvent.fromElement; + var initialInstance = nextHydratableInstance; - if (related) { - // If the related node is managed by React, we can assume that we have - // already dispatched the corresponding events during its mouseout. - if ( - getClosestInstanceFromNode(related) || - isContainerMarkedAsRoot(related) - ) { - return; - } - } + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableSuspenseInstance(); } - if (!isOutEvent && !isOverEvent) { - // Must not be a mouse or pointer in or out - ignoring. + var nextInstance = nextHydratableInstance; + + if (!nextInstance) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // Nothing to hydrate. Make it an insertion. + + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; return; } - var win; // TODO: why is this nullable in the types but we read from it? + var firstAttemptedInstance = nextInstance; - if (nativeEventTarget.window === nativeEventTarget) { - // `nativeEventTarget` is probably a window object. - win = nativeEventTarget; - } else { - // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. - var doc = nativeEventTarget.ownerDocument; + if (!tryHydrateSuspense(fiber, nextInstance)) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // 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. - if (doc) { - win = doc.defaultView || doc.parentWindow; - } else { - win = window; + nextHydratableInstance = getNextHydratableSibling(nextInstance); + var prevHydrationParentFiber = hydrationParentFiber; + + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableSuspenseInstance(); } + + if ( + !nextHydratableInstance || + !tryHydrateSuspense(fiber, nextHydratableInstance) + ) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + 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(prevHydrationParentFiber, firstAttemptedInstance); } +} - var from; - var to; +function prepareToHydrateHostInstance(fiber, hostContext) { + var instance = fiber.stateNode; + var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV; + var updatePayload = hydrateInstance( + instance, + fiber.type, + fiber.memoizedProps, + hostContext, + fiber, + shouldWarnIfMismatchDev + ); // TODO: Type this specific to this type of component. - if (isOutEvent) { - var _related = nativeEvent.relatedTarget || nativeEvent.toElement; + 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. - from = targetInst; - to = _related ? getClosestInstanceFromNode(_related) : null; + if (updatePayload !== null) { + return true; + } - if (to !== null) { - var nearestMounted = getNearestMountedFiber(to); - var tag = to.tag; + return false; +} - if ( - to !== nearestMounted || - (tag !== HostComponent && tag !== HostSingleton && tag !== HostText) - ) { - to = null; +function prepareToHydrateHostTextInstance(fiber) { + var textInstance = fiber.stateNode; + var textContent = fiber.memoizedProps; + var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV; + var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); + + if (shouldUpdate) { + // We assume that prepareToHydrateHostTextInstance is called in a context where the + // hydration parent is the parent host component of this host text. + var returnFiber = hydrationParentFiber; + + if (returnFiber !== null) { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode; + didNotMatchHydratedContainerTextInstance( + parentContainer, + textInstance, + textContent, // TODO: Delete this argument when we remove the legacy root API. + isConcurrentMode, + shouldWarnIfMismatchDev + ); + break; + } + + case HostSingleton: + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; + + var _isConcurrentMode2 = + (returnFiber.mode & ConcurrentMode) !== NoMode; + + didNotMatchHydratedTextInstance( + parentType, + parentProps, + parentInstance, + textInstance, + textContent, // TODO: Delete this argument when we remove the legacy root API. + _isConcurrentMode2, + shouldWarnIfMismatchDev + ); + break; + } } } - } else { - // Moving to a node from outside the window. - from = null; - to = targetInst; } - if (from === to) { - // Nothing pertains to our managed components. - return; - } + return shouldUpdate; +} - var SyntheticEventCtor = SyntheticMouseEvent; - var leaveEventType = "onMouseLeave"; - var enterEventType = "onMouseEnter"; - var eventTypePrefix = "mouse"; +function prepareToHydrateHostSuspenseInstance(fiber) { + var suspenseState = fiber.memoizedState; + var suspenseInstance = + suspenseState !== null ? suspenseState.dehydrated : null; - if (domEventName === "pointerout" || domEventName === "pointerover") { - SyntheticEventCtor = SyntheticPointerEvent; - leaveEventType = "onPointerLeave"; - enterEventType = "onPointerEnter"; - eventTypePrefix = "pointer"; + if (!suspenseInstance) { + throw new Error( + "Expected to have a hydrated suspense instance. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } - var fromNode = from == null ? win : getNodeFromInstance(from); - var toNode = to == null ? win : getNodeFromInstance(to); - var leave = new SyntheticEventCtor( - leaveEventType, - eventTypePrefix + "leave", - from, - nativeEvent, - nativeEventTarget - ); - leave.target = fromNode; - leave.relatedTarget = toNode; - var enter = null; // We should only process this nativeEvent if we are processing - // the first ancestor. Next time, we will ignore the event. + hydrateSuspenseInstance(suspenseInstance, fiber); +} - var nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget); +function skipPastDehydratedSuspenseInstance(fiber) { + var suspenseState = fiber.memoizedState; + var suspenseInstance = + suspenseState !== null ? suspenseState.dehydrated : null; - if (nativeTargetInst === targetInst) { - var enterEvent = new SyntheticEventCtor( - enterEventType, - eventTypePrefix + "enter", - to, - nativeEvent, - nativeEventTarget + if (!suspenseInstance) { + throw new Error( + "Expected to have a hydrated suspense instance. " + + "This error is likely caused by a bug in React. Please file an issue." ); - enterEvent.target = toNode; - enterEvent.relatedTarget = fromNode; - enter = enterEvent; } - accumulateEnterLeaveTwoPhaseListeners(dispatchQueue, leave, enter, from, to); + return getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); } -/** - * 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 - ); -} +function popToNextHostParent(fiber) { + hydrationParentFiber = fiber.return; -var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] + while (hydrationParentFiber) { + switch (hydrationParentFiber.tag) { + case HostRoot: + case HostSingleton: + rootOrSingletonContext = true; + return; -/** - * 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. - */ + case HostComponent: + case SuspenseComponent: + rootOrSingletonContext = false; + return; -function shallowEqual(objA, objB) { - if (objectIs(objA, objB)) { - return true; + default: + hydrationParentFiber = hydrationParentFiber.return; + } } +} - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { +function popHydrationState(fiber) { + if (fiber !== hydrationParentFiber) { + // We're deeper than the current hydration context, inside an inserted + // tree. return false; } - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); - - if (keysA.length !== keysB.length) { + 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; - } // Test for A's keys different from B. + } - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + var shouldClear = false; + { + // With float we never clear the Root, or Singleton instances. We also do not clear Instances + // that have singleton text content if ( - !hasOwnProperty.call(objB, currentKey) || - !objectIs(objA[currentKey], objB[currentKey]) + fiber.tag !== HostRoot && + fiber.tag !== HostSingleton && + !( + fiber.tag === HostComponent && + shouldSetTextContent(fiber.type, fiber.memoizedProps) + ) ) { - return false; + shouldClear = true; } } + if (shouldClear) { + var nextInstance = nextHydratableInstance; + + if (nextInstance) { + if (shouldClientRenderOnMismatch(fiber)) { + warnIfUnhydratedTailNodes(fiber); + throwOnHydrationMismatch(); + } else { + while (nextInstance) { + deleteHydratableInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); + } + } + } + } + + popToNextHostParent(fiber); + + if (fiber.tag === SuspenseComponent) { + nextHydratableInstance = skipPastDehydratedSuspenseInstance(fiber); + } else { + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; + } + return true; } -var skipSelectionChangeEvent = - canUseDOM && "documentMode" in document && document.documentMode <= 11; - -function registerEvents() { - registerTwoPhaseEvent("onSelect", [ - "focusout", - "contextmenu", - "dragend", - "focusin", - "keydown", - "keyup", - "mousedown", - "mouseup", - "selectionchange" - ]); +function hasUnhydratedTailNodes() { + return isHydrating && nextHydratableInstance !== null; } -var activeElement = null; -var activeElementInst = null; -var lastSelection = null; -var mouseDown = false; -/** - * Get an object which is a unique representation of the current selection. - * - * The return value will not be consistent across nodes or browsers, but - * two identical selections on the same node will return identical objects. - */ +function warnIfUnhydratedTailNodes(fiber) { + var nextInstance = nextHydratableInstance; -function getSelection(node) { - if ("selectionStart" in node && hasSelectionCapabilities(node)) { - return { - start: node.selectionStart, - end: node.selectionEnd - }; - } else { - var win = (node.ownerDocument && node.ownerDocument.defaultView) || window; - var selection = win.getSelection(); - return { - anchorNode: selection.anchorNode, - anchorOffset: selection.anchorOffset, - focusNode: selection.focusNode, - focusOffset: selection.focusOffset - }; + while (nextInstance) { + warnUnhydratedInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); } } -/** - * Get document associated with the event target. - */ -function getEventTargetDocument(eventTarget) { - return eventTarget.window === eventTarget - ? eventTarget.document - : eventTarget.nodeType === DOCUMENT_NODE - ? eventTarget - : eventTarget.ownerDocument; +function resetHydrationState() { + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; + didSuspendOrErrorDEV = false; } -/** - * Poll selection to see whether it's changed. - * - * @param {object} nativeEvent - * @param {object} nativeEventTarget - * @return {?SyntheticEvent} - */ -function constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) { - // Ensure we have the right element, and that the user is not dragging a - // selection (this matches native `select` event behavior). In HTML5, select - // fires only on input and textarea thus if there's no focused element we - // won't dispatch. - var doc = getEventTargetDocument(nativeEventTarget); +function upgradeHydrationErrorsToRecoverable() { + if (hydrationErrors !== null) { + // Successfully completed a forced client render. The errors that occurred + // during the hydration attempt are now recovered. We will log them in + // commit phase, once the entire tree has finished. + queueRecoverableErrors(hydrationErrors); + hydrationErrors = null; + } +} - if ( - mouseDown || - activeElement == null || - activeElement !== getActiveElement(doc) - ) { - return; - } // Only fire when selection has actually changed. +function getIsHydrating() { + return isHydrating; +} - var currentSelection = getSelection(activeElement); +function queueHydrationError(error) { + if (hydrationErrors === null) { + hydrationErrors = [error]; + } else { + hydrationErrors.push(error); + } +} - if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { - lastSelection = currentSelection; - var listeners = accumulateTwoPhaseListeners(activeElementInst, "onSelect"); +// we wait until the current render is over (either finished or interrupted) +// before adding it to the fiber/hook queue. Push to this array so we can +// access the queue, fiber, update, et al later. - if (listeners.length > 0) { - var event = new SyntheticEvent( - "onSelect", - "select", - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); - event.target = activeElement; - } - } -} -/** - * This plugin creates an `onSelect` event that normalizes select events - * across form elements. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - contentEditable - * - * This differs from native browser implementations in the following ways: - * - Fires on contentEditable fields as well as inputs. - * - Fires for collapsed selection. - * - Fires after user input. - */ +var concurrentQueues = []; +var concurrentQueuesIndex = 0; +var concurrentlyUpdatedLanes = NoLanes; +function finishQueueingConcurrentUpdates() { + var endIndex = concurrentQueuesIndex; + concurrentQueuesIndex = 0; + concurrentlyUpdatedLanes = NoLanes; + var i = 0; -function extractEvents$2( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var targetNode = targetInst ? getNodeFromInstance(targetInst) : window; + while (i < endIndex) { + var fiber = concurrentQueues[i]; + concurrentQueues[i++] = null; + var queue = concurrentQueues[i]; + concurrentQueues[i++] = null; + var update = concurrentQueues[i]; + concurrentQueues[i++] = null; + var lane = concurrentQueues[i]; + concurrentQueues[i++] = null; - switch (domEventName) { - // Track the input node that has focus. - case "focusin": - if ( - isTextInputElement(targetNode) || - targetNode.contentEditable === "true" - ) { - activeElement = targetNode; - activeElementInst = targetInst; - lastSelection = null; + if (queue !== null && update !== null) { + var pending = queue.pending; + + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; } - break; + queue.pending = update; + } - case "focusout": - activeElement = null; - activeElementInst = null; - lastSelection = null; - break; - // Don't fire the event while the user is dragging. This matches the - // semantics of the native select event. + if (lane !== NoLane) { + markUpdateLaneFromFiberToRoot(fiber, update, lane); + } + } +} +function getConcurrentlyUpdatedLanes() { + return concurrentlyUpdatedLanes; +} - case "mousedown": - mouseDown = true; - break; +function enqueueUpdate$1(fiber, queue, update, lane) { + // Don't update the `childLanes` on the return path yet. If we already in + // the middle of rendering, wait until after it has completed. + concurrentQueues[concurrentQueuesIndex++] = fiber; + concurrentQueues[concurrentQueuesIndex++] = queue; + concurrentQueues[concurrentQueuesIndex++] = update; + concurrentQueues[concurrentQueuesIndex++] = lane; + concurrentlyUpdatedLanes = mergeLanes(concurrentlyUpdatedLanes, lane); // The fiber's `lane` field is used in some places to check if any work is + // scheduled, to perform an eager bailout, so we need to update it immediately. + // TODO: We should probably move this to the "shared" queue instead. - case "contextmenu": - case "mouseup": - case "dragend": - mouseDown = false; - constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget); - break; - // Chrome and IE fire non-standard event when selection is changed (and - // sometimes when it hasn't). IE's event fires out of order with respect - // to key and input events on deletion, so we discard it. - // - // Firefox doesn't support selectionchange, so check selection status - // after each key entry. The selection changes after keydown and before - // keyup, but we check on keydown as well in the case of holding down a - // key, when multiple keydown events are fired but only one keyup is. - // This is also our approach for IE handling, for the reason above. + fiber.lanes = mergeLanes(fiber.lanes, lane); + var alternate = fiber.alternate; - case "selectionchange": - if (skipSelectionChangeEvent) { - break; - } + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } +} - // falls through +function enqueueConcurrentHookUpdate(fiber, queue, update, lane) { + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); + return getRootForUpdatedFiber(fiber); +} +function enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update) { + // This function is used to queue an update that doesn't need a rerender. The + // only reason we queue it is in case there's a subsequent higher priority + // update that causes it to be rebased. + var lane = NoLane; + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); // Usually we can rely on the upcoming render phase to process the concurrent + // queue. However, since this is a bail out, we're not scheduling any work + // here. So the update we just queued will leak until something else happens + // to schedule work (if ever). + // + // Check if we're currently in the middle of rendering a tree, and if not, + // process the queue immediately to prevent a leak. - case "keydown": - case "keyup": - constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget); + var isConcurrentlyRendering = getWorkInProgressRoot() !== null; + + if (!isConcurrentlyRendering) { + finishQueueingConcurrentUpdates(); } } +function enqueueConcurrentClassUpdate(fiber, queue, update, lane) { + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); + return getRootForUpdatedFiber(fiber); +} +function enqueueConcurrentRenderForLane(fiber, lane) { + enqueueUpdate$1(fiber, null, null, lane); + return getRootForUpdatedFiber(fiber); +} // Calling this function outside this module should only be done for backwards +// compatibility and should always be accompanied by a warning. -/** - * Generate a mapping of standard vendor prefixes using the defined style property and event name. - * - * @param {string} styleProp - * @param {string} eventName - * @returns {object} - */ - -function makePrefixMap(styleProp, eventName) { - var prefixes = {}; - prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); - prefixes["Webkit" + styleProp] = "webkit" + eventName; - prefixes["Moz" + styleProp] = "moz" + eventName; - return prefixes; +function unsafe_markUpdateLaneFromFiberToRoot(sourceFiber, lane) { + // NOTE: For Hyrum's Law reasons, if an infinite update loop is detected, it + // should throw before `markUpdateLaneFromFiberToRoot` is called. But this is + // undefined behavior and we can change it if we need to; it just so happens + // that, at the time of this writing, there's an internal product test that + // happens to rely on this. + var root = getRootForUpdatedFiber(sourceFiber); + markUpdateLaneFromFiberToRoot(sourceFiber, null, lane); + return root; } -/** - * A list of event names to a configurable list of vendor prefixes. - */ -var vendorPrefixes = { - animationend: makePrefixMap("Animation", "AnimationEnd"), - animationiteration: makePrefixMap("Animation", "AnimationIteration"), - animationstart: makePrefixMap("Animation", "AnimationStart"), - transitionend: makePrefixMap("Transition", "TransitionEnd") -}; -/** - * Event names that have already been detected and prefixed (if applicable). - */ +function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { + // Update the source fiber's lanes + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); + var alternate = sourceFiber.alternate; -var prefixedEventNames = {}; -/** - * Element to check for prefixes on. - */ + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } // Walk the parent path to the root and update the child lanes. -var style = {}; -/** - * Bootstrap if a DOM exists. - */ + var isHidden = false; + var parent = sourceFiber.return; + var node = sourceFiber; -if (canUseDOM) { - style = document.createElement("div").style; // On some platforms, in particular some releases of Android 4.x, - // the un-prefixed "animation" and "transition" properties are defined on the - // style object but the events that fire will still be prefixed, so we need - // to check if the un-prefixed events are usable, and if not remove them from the map. + while (parent !== null) { + parent.childLanes = mergeLanes(parent.childLanes, lane); + alternate = parent.alternate; - if (!("AnimationEvent" in window)) { - delete vendorPrefixes.animationend.animation; - delete vendorPrefixes.animationiteration.animation; - delete vendorPrefixes.animationstart.animation; - } // Same as above + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, lane); + } - if (!("TransitionEvent" in window)) { - delete vendorPrefixes.transitionend.transition; + if (parent.tag === OffscreenComponent) { + // Check if this offscreen boundary is currently hidden. + // + // The instance may be null if the Offscreen parent was unmounted. Usually + // the parent wouldn't be reachable in that case because we disconnect + // fibers from the tree when they are deleted. However, there's a weird + // edge case where setState is called on a fiber that was interrupted + // before it ever mounted. Because it never mounts, it also never gets + // deleted. Because it never gets deleted, its return pointer never gets + // disconnected. Which means it may be attached to a deleted Offscreen + // parent node. (This discovery suggests it may be better for memory usage + // if we don't attach the `return` pointer until the commit phase, though + // in order to do that we'd need some other way to track the return + // pointer during the initial render, like on the stack.) + // + // This case is always accompanied by a warning, but we still need to + // account for it. (There may be other cases that we haven't discovered, + // too.) + var offscreenInstance = parent.stateNode; + + if ( + offscreenInstance !== null && + !(offscreenInstance._visibility & OffscreenVisible) + ) { + isHidden = true; + } + } + + node = parent; + parent = parent.return; } -} -/** - * Attempts to determine the correct vendor prefixed event name. - * - * @param {string} eventName - * @returns {string} - */ -function getVendorPrefixedEventName(eventName) { - if (prefixedEventNames[eventName]) { - return prefixedEventNames[eventName]; - } else if (!vendorPrefixes[eventName]) { - return eventName; + if (isHidden && update !== null && node.tag === HostRoot) { + var root = node.stateNode; + markHiddenUpdate(root, update, lane); } +} - var prefixMap = vendorPrefixes[eventName]; +function getRootForUpdatedFiber(sourceFiber) { + // TODO: We will detect and infinite update loop and throw even if this fiber + // has already unmounted. This isn't really necessary but it happens to be the + // current behavior we've used for several release cycles. Consider not + // performing this check if the updated fiber already unmounted, since it's + // not possible for that to cause an infinite update loop. + throwIfInfiniteUpdateLoopDetected(); // When a setState happens, we must ensure the root is scheduled. Because + // update queues do not have a backpointer to the root, the only way to do + // this currently is to walk up the return path. This used to not be a big + // deal because we would have to walk up the return path to set + // the `childLanes`, anyway, but now those two traversals happen at + // different times. + // TODO: Consider adding a `root` backpointer on the update queue. - for (var styleProp in prefixMap) { - if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { - return (prefixedEventNames[eventName] = prefixMap[styleProp]); - } + detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); + var node = sourceFiber; + var parent = node.return; + + while (parent !== null) { + detectUpdateOnUnmountedFiber(sourceFiber, node); + node = parent; + parent = node.return; } - return eventName; + return node.tag === HostRoot ? node.stateNode : null; } -var ANIMATION_END = getVendorPrefixedEventName("animationend"); -var ANIMATION_ITERATION = getVendorPrefixedEventName("animationiteration"); -var ANIMATION_START = getVendorPrefixedEventName("animationstart"); -var TRANSITION_END = getVendorPrefixedEventName("transitionend"); +function detectUpdateOnUnmountedFiber(sourceFiber, parent) { + { + var alternate = parent.alternate; -var topLevelEventsToReactNames = new Map(); // NOTE: Capitalization is important in this list! -// -// E.g. it needs "pointerDown", not "pointerdown". -// This is because we derive both React name ("onPointerDown") -// and DOM name ("pointerdown") from the same list. -// -// Exceptions that don't match this convention are listed separately. -// -// prettier-ignore + if ( + alternate === null && + (parent.flags & (Placement | Hydrating)) !== NoFlags$1 + ) { + warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); + } + } +} -var simpleEventPluginEvents = ['abort', 'auxClick', 'cancel', 'canPlay', 'canPlayThrough', 'click', 'close', 'contextMenu', 'copy', 'cut', 'drag', 'dragEnd', 'dragEnter', 'dragExit', 'dragLeave', 'dragOver', 'dragStart', 'drop', 'durationChange', 'emptied', 'encrypted', 'ended', 'error', 'gotPointerCapture', 'input', 'invalid', 'keyDown', 'keyPress', 'keyUp', 'load', 'loadedData', 'loadedMetadata', 'loadStart', 'lostPointerCapture', 'mouseDown', 'mouseMove', 'mouseOut', 'mouseOver', 'mouseUp', 'paste', 'pause', 'play', 'playing', 'pointerCancel', 'pointerDown', 'pointerMove', 'pointerOut', 'pointerOver', 'pointerUp', 'progress', 'rateChange', 'reset', 'resize', 'seeked', 'seeking', 'stalled', 'submit', 'suspend', 'timeUpdate', 'touchCancel', 'touchEnd', 'touchStart', 'volumeChange', 'scroll', 'toggle', 'touchMove', 'waiting', 'wheel']; +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; +var didWarnUpdateInsideUpdate; +var currentlyProcessingQueue; { - // Special case: these two events don't have on* React handler - // and are only accessible via the createEventHandle API. - topLevelEventsToReactNames.set("beforeblur", null); - topLevelEventsToReactNames.set("afterblur", null); + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; } -function registerSimpleEvent(domEventName, reactName) { - topLevelEventsToReactNames.set(domEventName, reactName); - registerTwoPhaseEvent(reactName, [domEventName]); +function initializeUpdateQueue(fiber) { + var queue = { + baseState: fiber.memoizedState, + firstBaseUpdate: null, + lastBaseUpdate: null, + shared: { + pending: null, + lanes: NoLanes, + hiddenCallbacks: null + }, + callbacks: null + }; + fiber.updateQueue = queue; } +function cloneUpdateQueue(current, workInProgress) { + // Clone the update queue from current. Unless it's already a clone. + var queue = workInProgress.updateQueue; + var currentQueue = current.updateQueue; -function registerSimpleEvents() { - for (var i = 0; i < simpleEventPluginEvents.length; i++) { - var eventName = simpleEventPluginEvents[i]; - var domEventName = eventName.toLowerCase(); - var capitalizedEvent = eventName[0].toUpperCase() + eventName.slice(1); - registerSimpleEvent(domEventName, "on" + capitalizedEvent); - } // Special cases where event names don't match. - - registerSimpleEvent(ANIMATION_END, "onAnimationEnd"); - registerSimpleEvent(ANIMATION_ITERATION, "onAnimationIteration"); - registerSimpleEvent(ANIMATION_START, "onAnimationStart"); - registerSimpleEvent("dblclick", "onDoubleClick"); - registerSimpleEvent("focusin", "onFocus"); - registerSimpleEvent("focusout", "onBlur"); - registerSimpleEvent(TRANSITION_END, "onTransitionEnd"); + if (queue === currentQueue) { + var clone = { + baseState: currentQueue.baseState, + firstBaseUpdate: currentQueue.firstBaseUpdate, + lastBaseUpdate: currentQueue.lastBaseUpdate, + shared: currentQueue.shared, + callbacks: null + }; + workInProgress.updateQueue = clone; + } } +function createUpdate(lane) { + var update = { + lane: lane, + tag: UpdateState, + payload: null, + callback: null, + next: null + }; + return update; +} +function enqueueUpdate(fiber, update, lane) { + var updateQueue = fiber.updateQueue; -function extractEvents$1( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var reactName = topLevelEventsToReactNames.get(domEventName); - - if (reactName === undefined) { - return; + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; } - var SyntheticEventCtor = SyntheticEvent; - var reactEventType = domEventName; + var sharedQueue = updateQueue.shared; - switch (domEventName) { - case "keypress": - // Firefox creates a keypress event for function keys too. This removes - // the unwanted keypress events. Enter is however both printable and - // non-printable. One would expect Tab to be as well (but it isn't). - if (getEventCharCode(nativeEvent) === 0) { - return; - } + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); - /* falls through */ + error( + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName + ); - case "keydown": - case "keyup": - SyntheticEventCtor = SyntheticKeyboardEvent; - break; + didWarnUpdateInsideUpdate = true; + } + } - case "focusin": - reactEventType = "focus"; - SyntheticEventCtor = SyntheticFocusEvent; - break; + if (isUnsafeClassRenderPhaseUpdate(fiber)) { + // This is an unsafe render phase update. Add directly to the update + // queue so we can process it immediately during the current render. + var pending = sharedQueue.pending; - case "focusout": - reactEventType = "blur"; - SyntheticEventCtor = SyntheticFocusEvent; - break; + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - case "beforeblur": - case "afterblur": - SyntheticEventCtor = SyntheticFocusEvent; - break; + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - case "click": - // Firefox creates a click event on right mouse clicks. This removes the - // unwanted click events. - if (nativeEvent.button === 2) { - return; - } + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); + } else { + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + } +} +function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - /* falls through */ + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return; + } - case "auxclick": - case "dblclick": - case "mousedown": - case "mousemove": - case "mouseup": // TODO: Disabled elements should not respond to mouse events + var sharedQueue = updateQueue.shared; - /* falls through */ + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - case "mouseout": - case "mouseover": - case "contextmenu": - SyntheticEventCtor = SyntheticMouseEvent; - break; + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - case "drag": - case "dragend": - case "dragenter": - case "dragexit": - case "dragleave": - case "dragover": - case "dragstart": - case "drop": - SyntheticEventCtor = SyntheticDragEvent; - break; + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - case "touchcancel": - case "touchend": - case "touchmove": - case "touchstart": - SyntheticEventCtor = SyntheticTouchEvent; - break; + markRootEntangled(root, newQueueLanes); + } +} +function enqueueCapturedUpdate(workInProgress, capturedUpdate) { + // Captured updates are updates that are thrown by a child during the render + // phase. They should be discarded if the render is aborted. Therefore, + // we should only put them on the work-in-progress queue, not the current one. + var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. - case ANIMATION_END: - case ANIMATION_ITERATION: - case ANIMATION_START: - SyntheticEventCtor = SyntheticAnimationEvent; - break; + var current = workInProgress.alternate; - case TRANSITION_END: - SyntheticEventCtor = SyntheticTransitionEvent; - break; + if (current !== null) { + var currentQueue = current.updateQueue; - case "scroll": - SyntheticEventCtor = SyntheticUIEvent; - break; + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; - case "wheel": - SyntheticEventCtor = SyntheticWheelEvent; - break; + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - case "copy": - case "cut": - case "paste": - SyntheticEventCtor = SyntheticClipboardEvent; - break; + do { + var clone = { + lane: update.lane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; - case "gotpointercapture": - case "lostpointercapture": - case "pointercancel": - case "pointerdown": - case "pointermove": - case "pointerout": - case "pointerover": - case "pointerup": - SyntheticEventCtor = SyntheticPointerEvent; - break; - } + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0; + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - if (eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) { - var listeners = accumulateEventHandleNonManagedNodeListeners( - // TODO: this cast may not make sense for events like - // "focus" where React listens to e.g. "focusin". - reactEventType, - targetContainer, - inCapturePhase - ); + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; + } - if (listeners.length > 0) { - // Intentionally create event lazily. - var event = new SyntheticEventCtor( - reactName, - reactEventType, - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); + queue = { + baseState: currentQueue.baseState, + firstBaseUpdate: newFirst, + lastBaseUpdate: newLast, + shared: currentQueue.shared, + callbacks: currentQueue.callbacks + }; + workInProgress.updateQueue = queue; + return; } - } else { - // Some events don't bubble in the browser. - // In the past, React has always bubbled them, but this can be surprising. - // We're going to try aligning closer to the browser behavior by not bubbling - // them in React either. We'll start by not bubbling onScroll, and then expand. - var accumulateTargetOnly = - !inCapturePhase && // TODO: ideally, we'd eventually add all events from - // nonDelegatedEvents list in DOMPluginEventSystem. - // Then we can remove this special list. - // This is a breaking change that can wait until React 18. - domEventName === "scroll"; - - var _listeners = accumulateSinglePhaseListeners( - targetInst, - reactName, - nativeEvent.type, - inCapturePhase, - accumulateTargetOnly, - nativeEvent - ); + } // Append the update to the end of the list. - if (_listeners.length > 0) { - // Intentionally create event lazily. - var _event = new SyntheticEventCtor( - reactName, - reactEventType, - null, - nativeEvent, - nativeEventTarget - ); + var lastBaseUpdate = queue.lastBaseUpdate; - dispatchQueue.push({ - event: _event, - listeners: _listeners - }); - } + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; } -} -registerSimpleEvents(); -registerEvents$1(); -registerEvents$2(); -registerEvents(); -registerEvents$3(); + queue.lastBaseUpdate = capturedUpdate; +} -function extractEvents( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance ) { - // TODO: we should remove the concept of a "SimpleEventPlugin". - // This is the basic functionality of the event system. All - // the other plugins are essentially polyfills. So the plugin - // should probably be inlined somewhere and have its logic - // be core the to event system. This would potentially allow - // us to ship builds of React without the polyfilled plugins below. - extractEvents$1( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer - ); - var shouldProcessPolyfillPlugins = - (eventSystemFlags & SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS) === 0; // We don't process these events unless we are in the - // event's native "bubble" phase, which means that we're - // not in the capture phase. That's because we emulate - // the capture phase here still. This is a trade-off, - // because in an ideal world we would not emulate and use - // the phases properly, like we do with the SimpleEvent - // plugin. However, the plugins below either expect - // emulation (EnterLeave) or use state localized to that - // plugin (BeforeInput, Change, Select). The state in - // these modules complicates things, as you'll essentially - // get the case where the capture phase event might change - // state, only for the following bubble event to come in - // later and not trigger anything as the state now - // invalidates the heuristics of the event plugin. We - // could alter all these plugins to work in such ways, but - // that might cause other unknown side-effects that we - // can't foresee right now. + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; - if (shouldProcessPolyfillPlugins) { - extractEvents$3( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractEvents$4( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractEvents$2( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractEvents$5( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - } -} // List of events that need to be individually attached to media elements. + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } -var mediaEventTypes = [ - "abort", - "canplay", - "canplaythrough", - "durationchange", - "emptied", - "encrypted", - "ended", - "error", - "loadeddata", - "loadedmetadata", - "loadstart", - "pause", - "play", - "playing", - "progress", - "ratechange", - "resize", - "seeked", - "seeking", - "stalled", - "suspend", - "timeupdate", - "volumechange", - "waiting" -]; // We should not delegate these events to the container, but rather -// set them on the actual target element itself. This is primarily -// because these events do not consistently bubble in the DOM. + var nextState = payload.call(instance, prevState, nextProps); -var nonDelegatedEvents = new Set( - ["cancel", "close", "invalid", "load", "scroll", "toggle"].concat( - mediaEventTypes - ) -); + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); -function executeDispatch(event, listener, currentTarget) { - var type = event.type || "unknown-event"; - event.currentTarget = currentTarget; - invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); - event.currentTarget = null; -} + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } -function processDispatchQueueItemsInOrder( - event, - dispatchListeners, - inCapturePhase -) { - var previousInstance; + exitDisallowedContextReadInDEV(); + } - if (inCapturePhase) { - for (var i = dispatchListeners.length - 1; i >= 0; i--) { - var _dispatchListeners$i = dispatchListeners[i], - instance = _dispatchListeners$i.instance, - currentTarget = _dispatchListeners$i.currentTarget, - listener = _dispatchListeners$i.listener; + return nextState; + } // State object - if (instance !== previousInstance && event.isPropagationStopped()) { - return; - } + return payload; + } - executeDispatch(event, listener, currentTarget); - previousInstance = instance; + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; } - } else { - for (var _i = 0; _i < dispatchListeners.length; _i++) { - var _dispatchListeners$_i = dispatchListeners[_i], - _instance = _dispatchListeners$_i.instance, - _currentTarget = _dispatchListeners$_i.currentTarget, - _listener = _dispatchListeners$_i.listener; + // Intentional fallthrough - if (_instance !== previousInstance && event.isPropagationStopped()) { - return; - } + case UpdateState: { + var _payload = update.payload; + var partialState; - executeDispatch(event, _listener, _currentTarget); - previousInstance = _instance; - } - } -} + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } -function processDispatchQueue(dispatchQueue, eventSystemFlags) { - var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0; + partialState = _payload.call(instance, prevState, nextProps); - for (var i = 0; i < dispatchQueue.length; i++) { - var _dispatchQueue$i = dispatchQueue[i], - event = _dispatchQueue$i.event, - listeners = _dispatchQueue$i.listeners; - processDispatchQueueItemsInOrder(event, listeners, inCapturePhase); // event system doesn't use pooling. - } // This would be a good time to rethrow if any of the event handlers threw. + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - rethrowCaughtError(); -} + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } -function dispatchEventsForPlugins( - domEventName, - eventSystemFlags, - nativeEvent, - targetInst, - targetContainer -) { - var nativeEventTarget = getEventTarget(nativeEvent); - var dispatchQueue = []; - extractEvents( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer - ); - processDispatchQueue(dispatchQueue, eventSystemFlags); -} + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; + } -function listenToNonDelegatedEvent(domEventName, targetElement) { - { - if (!nonDelegatedEvents.has(domEventName)) { - error( - 'Did not expect a listenToNonDelegatedEvent() call for "%s". ' + - "This is a bug in React. Please file an issue.", - domEventName - ); - } - } + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - var isCapturePhaseListener = false; - var listenerSet = getEventListenerSet(targetElement); - var listenerSetKey = getListenerSetKey(domEventName, isCapturePhaseListener); + return assign({}, prevState, partialState); + } - if (!listenerSet.has(listenerSetKey)) { - addTrappedEventListener( - targetElement, - domEventName, - IS_NON_DELEGATED, - isCapturePhaseListener - ); - listenerSet.add(listenerSetKey); - } -} -function listenToNativeEvent(domEventName, isCapturePhaseListener, target) { - { - if (nonDelegatedEvents.has(domEventName) && !isCapturePhaseListener) { - error( - 'Did not expect a listenToNativeEvent() call for "%s" in the bubble phase. ' + - "This is a bug in React. Please file an issue.", - domEventName - ); + case ForceUpdate: { + hasForceUpdate = true; + return prevState; } } - var eventSystemFlags = 0; + return prevState; +} - if (isCapturePhaseListener) { - eventSystemFlags |= IS_CAPTURE_PHASE; +function processUpdateQueue(workInProgress, props, instance, renderLanes) { + // This is always non-null on a ClassComponent or HostRoot + var queue = workInProgress.updateQueue; + hasForceUpdate = false; + + { + currentlyProcessingQueue = queue.shared; } - addTrappedEventListener( - target, - domEventName, - eventSystemFlags, - isCapturePhaseListener - ); -} // This is only used by createEventHandle when the -// target is not a DOM element. E.g. window. + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. -function listenToNativeEventForNonManagedEventTarget( - domEventName, - isCapturePhaseListener, - target -) { - var eventSystemFlags = IS_EVENT_HANDLE_NON_MANAGED_NODE; - var listenerSet = getEventListenerSet(target); - var listenerSetKey = getListenerSetKey(domEventName, isCapturePhaseListener); + var pendingQueue = queue.shared.pending; - if (!listenerSet.has(listenerSetKey)) { - if (isCapturePhaseListener) { - eventSystemFlags |= IS_CAPTURE_PHASE; - } + if (pendingQueue !== null) { + queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first + // and last so that it's non-circular. - addTrappedEventListener( - target, - domEventName, - eventSystemFlags, - isCapturePhaseListener - ); - listenerSet.add(listenerSetKey); - } -} -var listeningMarker = "_reactListening" + Math.random().toString(36).slice(2); -function listenToAllSupportedEvents(rootContainerElement) { - if (!rootContainerElement[listeningMarker]) { - rootContainerElement[listeningMarker] = true; - allNativeEvents.forEach(function (domEventName) { - // We handle selectionchange separately because it - // doesn't bubble and needs to be on the document. - if (domEventName !== "selectionchange") { - if (!nonDelegatedEvents.has(domEventName)) { - listenToNativeEvent(domEventName, false, rootContainerElement); - } - - listenToNativeEvent(domEventName, true, rootContainerElement); - } - }); - var ownerDocument = - rootContainerElement.nodeType === DOCUMENT_NODE - ? rootContainerElement - : rootContainerElement.ownerDocument; + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - if (ownerDocument !== null) { - // The selectionchange event also needs deduplication - // but it is attached to the document. - if (!ownerDocument[listeningMarker]) { - ownerDocument[listeningMarker] = true; - listenToNativeEvent("selectionchange", false, ownerDocument); - } + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; + } else { + lastBaseUpdate.next = firstPendingUpdate; } - } -} -function addTrappedEventListener( - targetContainer, - domEventName, - eventSystemFlags, - isCapturePhaseListener, - isDeferredListenerForLegacyFBSupport -) { - var listener = createEventListenerWrapperWithPriority( - targetContainer, - domEventName, - eventSystemFlags - ); // If passive option is not supported, then the event will be - // active and not passive. + lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then + // we need to transfer the updates to that queue, too. Because the base + // queue is a singly-linked list with no cycles, we can append to both + // lists and take advantage of structural sharing. + // TODO: Pass `current` as argument - var isPassiveListener = undefined; + var current = workInProgress.alternate; - if (passiveBrowserEventsSupported) { - // Browsers introduced an intervention, making these events - // passive by default on document. React doesn't bind them - // to document anymore, but changing this now would undo - // the performance wins from the change. So we emulate - // the existing behavior manually on the roots now. - // https://github.com/facebook/react/issues/19651 - if ( - domEventName === "touchstart" || - domEventName === "touchmove" || - domEventName === "wheel" - ) { - isPassiveListener = true; - } - } + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; - targetContainer = - enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport - ? targetContainer.ownerDocument - : targetContainer; - var unsubscribeListener; // When legacyFBSupport is enabled, it's for when we - // want to add a one time event listener to a container. - // This should only be used with enableLegacyFBSupport - // due to requirement to provide compatibility with - // internal FB www event tooling. This works by removing - // the event listener as soon as it is invoked. We could - // also attempt to use the {once: true} param on - // addEventListener, but that requires support and some - // browsers do not support this today, and given this is - // to support legacy code patterns, it's likely they'll - // need support for such browsers. + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } - if (enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport) { - var originalListener = listener; // $FlowFixMe[missing-this-annot] - // $FlowFixMe[definition-cycle] + currentQueue.lastBaseUpdate = lastPendingUpdate; + } + } + } // These values may change as we process the queue. - listener = function () { - removeEventListener(targetContainer, domEventName, unsubscribeListener); + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. - for ( - var _len = arguments.length, p = new Array(_len), _key = 0; - _key < _len; - _key++ - ) { - p[_key] = arguments[_key]; - } + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; - return originalListener.apply(this, p); - }; - } // TODO: There are too many combinations here. Consolidate them. + do { + // An extra OffscreenLane bit is added to updates that were made to + // a hidden tree, so that we can distinguish them from updates that were + // already there when the tree was hidden. + var updateLane = removeLanes(update.lane, OffscreenLane); + var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then + // it's not a "base" update and we should disregard the extra base lanes + // that were added to renderLanes when we entered the Offscreen tree. - if (isCapturePhaseListener) { - if (isPassiveListener !== undefined) { - unsubscribeListener = addEventCaptureListenerWithPassiveFlag( - targetContainer, - domEventName, - listener, - isPassiveListener - ); - } else { - unsubscribeListener = addEventCaptureListener( - targetContainer, - domEventName, - listener - ); - } - } else { - if (isPassiveListener !== undefined) { - unsubscribeListener = addEventBubbleListenerWithPassiveFlag( - targetContainer, - domEventName, - listener, - isPassiveListener - ); - } else { - unsubscribeListener = addEventBubbleListener( - targetContainer, - domEventName, - listener - ); - } - } -} + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); -function deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer) { - // We defer all click events with legacy FB support mode on. - // This means we add a one time event listener to trigger - // after the FB delegated listeners fire. - var isDeferredListenerForLegacyFBSupport = true; - addTrappedEventListener( - targetContainer, - domEventName, - IS_LEGACY_FB_SUPPORT_MODE, - false, - isDeferredListenerForLegacyFBSupport - ); -} + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + tag: update.tag, + payload: update.payload, + callback: update.callback, + next: null + }; -function isMatchingRootContainer(grandContainer, targetContainer) { - return ( - grandContainer === targetContainer || - (grandContainer.nodeType === COMMENT_NODE && - grandContainer.parentNode === targetContainer) - ); -} + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. -function dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - targetInst, - targetContainer -) { - var ancestorInst = targetInst; + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - if ( - (eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) === 0 && - (eventSystemFlags & IS_NON_DELEGATED) === 0 - ) { - var targetContainerNode = targetContainer; // If we are using the legacy FB support flag, we - // defer the event to the null with a one - // time event listener so we can defer the event. + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; - if ( - enableLegacyFBSupport && // If our event flags match the required flags for entering - // FB legacy mode and we are processing the "click" event, - // then we can defer the event to the "document", to allow - // for legacy FB support, where the expected behavior was to - // match React < 16 behavior of delegated clicks to the doc. - domEventName === "click" && - (eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0 && - !isReplayingEvent(nativeEvent) - ) { - deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer); - return; - } + if (callback !== null) { + workInProgress.flags |= Callback; - if (targetInst !== null) { - // The below logic attempts to work out if we need to change - // the target fiber to a different ancestor. We had similar logic - // in the legacy event system, except the big difference between - // systems is that the modern event system now has an event listener - // attached to each React Root and React Portal Root. Together, - // the DOM nodes representing these roots are the "rootContainer". - // To figure out which ancestor instance we should use, we traverse - // up the fiber tree from the target instance and attempt to find - // root boundaries that match that of our current "rootContainer". - // If we find that "rootContainer", we find the parent fiber - // sub-tree for that root and make that our ancestor instance. - var node = targetInst; + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; + } - mainLoop: while (true) { - if (node === null) { - return; + var callbacks = queue.callbacks; + + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } } + } // $FlowFixMe[incompatible-type] we bail out when we get a null - var nodeTag = node.tag; + update = update.next; - if (nodeTag === HostRoot || nodeTag === HostPortal) { - var container = node.stateNode.containerInfo; + if (update === null) { + pendingQueue = queue.shared.pending; - if (isMatchingRootContainer(container, targetContainerNode)) { - break; - } + if (pendingQueue === null) { + break; + } else { + // An update was scheduled from inside a reducer. Add the new + // pending updates to the end of the list and keep processing. + var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we + // unravel them when transferring them to the base queue. - if (nodeTag === HostPortal) { - // The target is a portal, but it's not the rootContainer we're looking for. - // Normally portals handle their own events all the way down to the root. - // So we should be able to stop now. However, we don't know if this portal - // was part of *our* root. - var grandNode = node.return; + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } + } + } while (true); - while (grandNode !== null) { - var grandTag = grandNode.tag; + if (newLastBaseUpdate === null) { + newBaseState = newState; + } - if (grandTag === HostRoot || grandTag === HostPortal) { - var grandContainer = grandNode.stateNode.containerInfo; + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; - if ( - isMatchingRootContainer(grandContainer, targetContainerNode) - ) { - // This is the rootContainer we're looking for and we found it as - // a parent of the Portal. That means we can ignore it because the - // Portal will bubble through to us. - return; - } - } + if (firstBaseUpdate === null) { + // `queue.lanes` is used for entangling transitions. We can set it back to + // zero once the queue is empty. + queue.shared.lanes = NoLanes; + } // 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. - grandNode = grandNode.return; - } - } // Now we need to find it's corresponding host fiber in the other - // tree. To do this we can use getClosestInstanceFromNode, but we - // need to validate that the fiber is a host instance, otherwise - // we need to traverse up through the DOM till we find the correct - // node that is from the other tree. + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; + } - while (container !== null) { - var parentNode = getClosestInstanceFromNode(container); + { + currentlyProcessingQueue = null; + } +} - if (parentNode === null) { - return; - } +function callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); + } - var parentTag = parentNode.tag; + callback.call(context); +} - if ( - parentTag === HostComponent || - parentTag === HostText || - parentTag === HostHoistable || - parentTag === HostSingleton - ) { - node = ancestorInst = parentNode; - continue mainLoop; - } +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} +function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - container = container.parentNode; - } - } + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - node = node.return; - } + if (existingHiddenCallbacks === null) { + updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; + } else { + updateQueue.shared.hiddenCallbacks = + existingHiddenCallbacks.concat(newHiddenCallbacks); } } +} +function commitHiddenCallbacks(updateQueue, context) { + // This component is switching from hidden -> visible. Commit any callbacks + // that were previously deferred. + var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; - batchedUpdates$1(function () { - return dispatchEventsForPlugins( - domEventName, - eventSystemFlags, - nativeEvent, - ancestorInst, - targetContainer - ); - }); + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; + + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); + } + } } +function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; -function createDispatchListener(instance, listener, currentTarget) { - return { - instance: instance, - listener: listener, - currentTarget: currentTarget - }; + if (callbacks !== null) { + updateQueue.callbacks = null; + + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } + } } -function accumulateSinglePhaseListeners( - targetFiber, - reactName, - nativeEventType, - inCapturePhase, - accumulateTargetOnly, - nativeEvent -) { - var captureName = reactName !== null ? reactName + "Capture" : null; - var reactEventName = inCapturePhase ? captureName : reactName; - var listeners = []; - var instance = targetFiber; - var lastHostComponent = null; // Accumulate all instances and listeners via the target -> root path. +/** + * 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. + */ - while (instance !== null) { - var _instance2 = instance, - stateNode = _instance2.stateNode, - tag = _instance2.tag; // Handle listeners that are on HostComponents (i.e.
) +function shallowEqual(objA, objB) { + if (objectIs(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++) { + var currentKey = keysA[i]; if ( - (tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton) && - stateNode !== null + !hasOwnProperty.call(objB, currentKey) || + !objectIs(objA[currentKey], objB[currentKey]) ) { - lastHostComponent = stateNode; // createEventHandle listeners + return false; + } + } - { - var eventHandlerListeners = getEventHandlerListeners(lastHostComponent); + return true; +} - if (eventHandlerListeners !== null) { - eventHandlerListeners.forEach(function (entry) { - if ( - entry.type === nativeEventType && - entry.capture === inCapturePhase - ) { - listeners.push( - createDispatchListener( - instance, - entry.callback, - lastHostComponent - ) - ); - } - }); - } - } // Standard React on* listeners, i.e. onClick or onClickCapture +var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} +}; - if (reactEventName !== null) { - var listener = getListener(instance, reactEventName); +{ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; - if (listener != null) { - listeners.push( - createDispatchListener(instance, listener, lastHostComponent) - ); - } + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; } - } else if ( - tag === ScopeComponent && - lastHostComponent !== null && - stateNode !== null - ) { - // Scopes - var reactScopeInstance = stateNode; - var _eventHandlerListeners = getEventHandlerListeners(reactScopeInstance); + node = node.return; + } - if (_eventHandlerListeners !== null) { - _eventHandlerListeners.forEach(function (entry) { - if ( - entry.type === nativeEventType && - entry.capture === inCapturePhase - ) { - listeners.push( - createDispatchListener( - instance, - entry.callback, - lastHostComponent - ) - ); - } - }); - } - } // If we are only accumulating events for the target, then we don't - // continue to propagate through the React fiber tree to find other - // listeners. + return maybeStrictRoot; + }; - if (accumulateTargetOnly) { - break; - } // If we are processing the onBeforeBlur event, then we need to take - // into consideration that part of the React tree might have been hidden - // or deleted (as we're invoking this event during commit). We can find - // this out by checking if intercept fiber set on the event matches the - // current instance fiber. In which case, we should clear all existing - // listeners. + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; - if (nativeEvent.type === "beforeblur") { - // $FlowFixMe[prop-missing] internal field - var detachedInterceptFiber = nativeEvent._detachedInterceptFiber; + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - if ( - detachedInterceptFiber !== null && - (detachedInterceptFiber === instance || - detachedInterceptFiber === instance.alternate) - ) { - listeners = []; - } + var didWarnAboutUnsafeLifecycles = new Set(); + + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; } - instance = instance.return; - } + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } - return listeners; -} // We should only use this function for: -// - BeforeInputEventPlugin -// - ChangeEventPlugin -// - SelectEventPlugin -// This is because we only process these plugins -// in the bubble phase, so we need to accumulate two -// phase event listeners (via emulation). + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); + } -function accumulateTwoPhaseListeners(targetFiber, reactName) { - var captureName = reactName + "Capture"; - var listeners = []; - var instance = targetFiber; // Accumulate all instances and listeners via the target -> root path. + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } - while (instance !== null) { - var _instance3 = instance, - stateNode = _instance3.stateNode, - tag = _instance3.tag; // Handle listeners that are on HostComponents (i.e.
) + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); + } if ( - (tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton) && - stateNode !== null + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true ) { - var currentTarget = stateNode; - var captureListener = getListener(instance, captureName); + pendingComponentWillUpdateWarnings.push(fiber); + } - if (captureListener != null) { - listeners.unshift( - createDispatchListener(instance, captureListener, currentTarget) - ); - } + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + } + }; - var bubbleListener = getListener(instance, reactName); + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - if (bubbleListener != null) { - listeners.push( - createDispatchListener(instance, bubbleListener, currentTarget) + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" ); - } + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; } - instance = instance.return; - } + var UNSAFE_componentWillMountUniqueNames = new Set(); - return listeners; -} + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; + } -function getParent(inst) { - if (inst === null) { - return null; - } + var componentWillReceivePropsUniqueNames = new Set(); - do { - // $FlowFixMe[incompatible-use] found when upgrading Flow - inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent && inst.tag !== HostSingleton); + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; + } - if (inst) { - return inst; - } + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); - return null; -} -/** - * Return the lowest common ancestor of A and B, or null if they are in - * different trees. - */ + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + } -function getLowestCommonAncestor(instA, instB) { - var nodeA = instA; - var nodeB = instB; - var depthA = 0; + var componentWillUpdateUniqueNames = new Set(); - for (var tempA = nodeA; tempA; tempA = getParent(tempA)) { - depthA++; - } + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } - var depthB = 0; + var UNSAFE_componentWillUpdateUniqueNames = new Set(); - for (var tempB = nodeB; tempB; tempB = getParent(tempB)) { - depthB++; - } // If A is deeper, crawl up. + if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { + pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { + UNSAFE_componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillUpdateWarnings = []; + } // Finally, we flush all the warnings + // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' - while (depthA - depthB > 0) { - nodeA = getParent(nodeA); - depthA--; - } // If B is deeper, crawl up. + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); - while (depthB - depthA > 0) { - nodeB = getParent(nodeB); - depthB--; - } // Walk in lockstep until we find a match. + error( + "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "\nPlease update the following components: %s", + sortedNames + ); + } - var depth = depthA; + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); - while (depth--) { - if (nodeA === nodeB || (nodeB !== null && nodeA === nodeB.alternate)) { - return nodeA; + error( + "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, " + + "refactor your code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "\nPlease update the following components: %s", + _sortedNames + ); } - nodeA = getParent(nodeA); - nodeB = getParent(nodeB); - } + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - return null; -} + error( + "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "\nPlease update the following components: %s", + _sortedNames2 + ); + } -function accumulateEnterLeaveListenersForEvent( - dispatchQueue, - event, - target, - common, - inCapturePhase -) { - var registrationName = event._reactName; - var listeners = []; - var instance = target; + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); - while (instance !== null) { - if (instance === common) { - break; + warn( + "componentWillMount has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames3 + ); } - var _instance4 = instance, - alternate = _instance4.alternate, - stateNode = _instance4.stateNode, - tag = _instance4.tag; + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames + ); - if (alternate !== null && alternate === common) { - break; + warn( + "componentWillReceiveProps has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, refactor your " + + "code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames4 + ); } - if ( - (tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton) && - stateNode !== null - ) { - var currentTarget = stateNode; + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); - if (inCapturePhase) { - var captureListener = getListener(instance, registrationName); + warn( + "componentWillUpdate has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames5 + ); + } + }; - if (captureListener != null) { - listeners.unshift( - createDispatchListener(instance, captureListener, currentTarget) - ); - } - } else if (!inCapturePhase) { - var bubbleListener = getListener(instance, registrationName); + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - if (bubbleListener != null) { - listeners.push( - createDispatchListener(instance, bubbleListener, currentTarget) - ); - } - } - } + var didWarnAboutLegacyContext = new Set(); - instance = instance.return; - } + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - if (listeners.length !== 0) { - dispatchQueue.push({ - event: event, - listeners: listeners - }); - } -} // We should only use this function for: -// - EnterLeaveEventPlugin -// This is because we only process this plugin -// in the bubble phase, so we need to accumulate two -// phase event listeners. + if (strictRoot === null) { + error( + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); -function accumulateEnterLeaveTwoPhaseListeners( - dispatchQueue, - leaveEvent, - enterEvent, - from, - to -) { - var common = from && to ? getLowestCommonAncestor(from, to) : null; + return; + } // Dedup strategy: Warn once per component. - if (from !== null) { - accumulateEnterLeaveListenersForEvent( - dispatchQueue, - leaveEvent, - from, - common, - false - ); - } + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } - if (to !== null && enterEvent !== null) { - accumulateEnterLeaveListenersForEvent( - dispatchQueue, - enterEvent, - to, - common, - true - ); - } -} -function accumulateEventHandleNonManagedNodeListeners( - reactEventType, - currentTarget, - inCapturePhase -) { - var listeners = []; - var eventListeners = getEventHandlerListeners(currentTarget); + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - if (eventListeners !== null) { - eventListeners.forEach(function (entry) { - if (entry.type === reactEventType && entry.capture === inCapturePhase) { - listeners.push( - createDispatchListener(null, entry.callback, currentTarget) - ); + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); } - }); - } - return listeners; -} -function getListenerSetKey(domEventName, capture) { - return domEventName + "__" + (capture ? "capture" : "bubble"); -} + warningsForRoot.push(fiber); + } + }; -// This is imported by the event replaying implementation in React DOM. It's -// in a separate file to break a circular dependency between the renderer and -// the reconciler. -function isRootDehydrated(root) { - var currentState = root.current.memoizedState; - return currentState.isDehydrated; -} - -var _attemptSynchronousHydration; + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; + } -function setAttemptSynchronousHydration(fn) { - _attemptSynchronousHydration = fn; -} -function attemptSynchronousHydration$1(fiber) { - _attemptSynchronousHydration(fiber); -} -var attemptDiscreteHydration$1; -function setAttemptDiscreteHydration(fn) { - attemptDiscreteHydration$1 = fn; -} -var attemptContinuousHydration$1; -function setAttemptContinuousHydration(fn) { - attemptContinuousHydration$1 = fn; -} -var attemptHydrationAtCurrentPriority$1; -function setAttemptHydrationAtCurrentPriority(fn) { - attemptHydrationAtCurrentPriority$1 = fn; -} -var getCurrentUpdatePriority; -function setGetCurrentUpdatePriority(fn) { - getCurrentUpdatePriority = fn; -} -var attemptHydrationAtPriority; -function setAttemptHydrationAtPriority(fn) { - attemptHydrationAtPriority = fn; -} // TODO: Upgrade this definition once we're on a newer version of Flow that -// has this definition built-in. + var firstFiber = fiberArray[0]; + var uniqueNames = new Set(); + fiberArray.forEach(function (fiber) { + uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + var sortedNames = setToSortedString(uniqueNames); -var hasScheduledReplayAttempt = false; // The queue of discrete events to be replayed. + try { + setCurrentFiber(firstFiber); -var queuedDiscreteEvents = []; // Indicates if any continuous event targets are non-null for early bailout. -// if the last target was dehydrated. + error( + "Legacy context API has been detected within a strict-mode tree." + + "\n\nThe old API will be supported in all 16.x releases, but applications " + + "using it should migrate to the new version." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", + sortedNames + ); + } finally { + resetCurrentFiber(); + } + }); + }; -var queuedFocus = null; -var queuedDrag = null; -var queuedMouse = null; // For pointer events there can be one latest event per pointerId. + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; +} -var queuedPointers = new Map(); -var queuedPointerCaptures = new Map(); // We could consider replaying selectionchange and touchmoves too. +var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we +// detect this is caught by userspace, we'll log a warning in development. -var queuedExplicitHydrationTargets = []; -function hasQueuedDiscreteEvents() { - return queuedDiscreteEvents.length > 0; +var SuspenseException = new Error( + "Suspense Exception: This is not a real error! It's an implementation " + + "detail of `use` to interrupt the current render. You must either " + + "rethrow it immediately, or move the `use` call outside of the " + + "`try/catch` block. Capturing without rethrowing will lead to " + + "unexpected behavior.\n\n" + + "To handle async errors, wrap your component in an error boundary, or " + + "call the promise's `.catch` method and pass the result to `use`" +); +function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + return []; } -var discreteReplayableEvents = [ - "mousedown", - "mouseup", - "touchcancel", - "touchend", - "touchstart", - "auxclick", - "dblclick", - "pointercancel", - "pointerdown", - "pointerup", - "dragend", - "dragstart", - "drop", - "compositionend", - "compositionstart", - "keydown", - "keypress", - "keyup", - "input", - "textInput", // Intentionally camelCase - "copy", - "cut", - "paste", - "click", - "change", - "contextmenu", - "reset", - "submit" -]; -function isDiscreteEventThatRequiresHydration(eventType) { - return discreteReplayableEvents.indexOf(eventType) > -1; +function isThenableResolved(thenable) { + var status = thenable.status; + return status === "fulfilled" || status === "rejected"; } -function createQueuedReplayableEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - return { - blockedOn: blockedOn, - domEventName: domEventName, - eventSystemFlags: eventSystemFlags, - nativeEvent: nativeEvent, - targetContainers: [targetContainer] - }; -} +function noop() {} -function queueDiscreteEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - return; +function trackUsedThenable(thenableState, thenable, index) { + if (ReactCurrentActQueue$2.current !== null) { + ReactCurrentActQueue$2.didUsePromise = true; } - var queuedEvent = createQueuedReplayableEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - queuedDiscreteEvents.push(queuedEvent); - - if (queuedDiscreteEvents.length === 1) { - // If this was the first discrete event, we might be able to - // synchronously unblock it so that preventDefault still works. - while (queuedEvent.blockedOn !== null) { - var fiber = getInstanceFromNode(queuedEvent.blockedOn); + var previous = thenableState[index]; - if (fiber === null) { - break; - } + if (previous === undefined) { + thenableState.push(thenable); + } else { + if (previous !== thenable) { + // Reuse the previous thenable, and drop the new one. We can assume + // they represent the same value, because components are idempotent. + // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. + thenable.then(noop, noop); + thenable = previous; + } + } // We use an expando to track the status and result of a thenable so that we + // can synchronously unwrap the value. Think of this as an extension of the + // Promise API, or a custom interface that is a superset of Thenable. + // + // If the thenable doesn't have a status, set it to "pending" and attach + // a listener that will update its status and result when it resolves. - attemptSynchronousHydration$1(fiber); + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; + } - if (queuedEvent.blockedOn === null) { - // We got unblocked by hydration. Let's try again. - replayUnblockedEvents(); // If we're reblocked, on an inner boundary, we might need - // to attempt hydrating that one. + case "rejected": { + var rejectedError = thenable.reason; + throw rejectedError; + } - continue; + default: { + if (typeof thenable.status === "string") { + // Only instrument the thenable if the status if not defined. If + // it's defined, but an unknown value, assume it's been instrumented by + // some custom userspace implementation. We treat it as "pending". + // Attach a dummy listener, to ensure that any lazy initialization can + // happen. Flight lazily parses JSON when the value is actually awaited. + thenable.then(noop, noop); } else { - // We're still blocked from hydration, we have to give up - // and replay later. - break; - } - } - } -} // Resets the replaying for this type of continuous event to no event. + var pendingThenable = thenable; + pendingThenable.status = "pending"; + pendingThenable.then( + function (fulfilledValue) { + if (thenable.status === "pending") { + var fulfilledThenable = thenable; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = fulfilledValue; + } + }, + function (error) { + if (thenable.status === "pending") { + var rejectedThenable = thenable; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; + } + } + ); + } // Check one more time in case the thenable resolved synchronously. -function clearIfContinuousEvent(domEventName, nativeEvent) { - switch (domEventName) { - case "focusin": - case "focusout": - queuedFocus = null; - break; + switch (thenable.status) { + case "fulfilled": { + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } - case "dragenter": - case "dragleave": - queuedDrag = null; - break; + case "rejected": { + var rejectedThenable = thenable; + throw rejectedThenable.reason; + } + } // Suspend. + // + // Throwing here is an implementation detail that allows us to unwind the + // call stack. But we shouldn't allow it to leak into userspace. Throw an + // opaque placeholder value instead of the actual thenable. If it doesn't + // get captured by the work loop, log a warning, because that means + // something in userspace must have caught it. - case "mouseover": - case "mouseout": - queuedMouse = null; - break; + suspendedThenable = thenable; - case "pointerover": - case "pointerout": { - var pointerId = nativeEvent.pointerId; - queuedPointers.delete(pointerId); - break; - } + { + needsToResetSuspendedThenableDEV = true; + } - case "gotpointercapture": - case "lostpointercapture": { - var _pointerId = nativeEvent.pointerId; - queuedPointerCaptures.delete(_pointerId); - break; + throw SuspenseException; } } -} +} // This is used to track the actual thenable that suspended so it can be +// passed to the rest of the Suspense implementation — which, for historical +// reasons, expects to receive a thenable. -function accumulateOrCreateContinuousQueuedReplayableEvent( - existingQueuedEvent, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - if ( - existingQueuedEvent === null || - existingQueuedEvent.nativeEvent !== nativeEvent - ) { - var queuedEvent = createQueuedReplayableEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent +var suspendedThenable = null; +var needsToResetSuspendedThenableDEV = false; +function getSuspendedThenable() { + // This is called right after `use` suspends by throwing an exception. `use` + // throws an opaque value instead of the thenable itself so that it can't be + // caught in userspace. Then the work loop accesses the actual thenable using + // this function. + if (suspendedThenable === null) { + throw new Error( + "Expected a suspended thenable. This is a bug in React. Please file " + + "an issue." ); + } - if (blockedOn !== null) { - var fiber = getInstanceFromNode(blockedOn); - - if (fiber !== null) { - // Attempt to increase the priority of this target. - attemptContinuousHydration$1(fiber); - } - } - - return queuedEvent; - } // If we have already queued this exact event, then it's because - // the different event systems have different DOM event listeners. - // We can accumulate the flags, and the targetContainers, and - // store a single event to be replayed. - - existingQueuedEvent.eventSystemFlags |= eventSystemFlags; - var targetContainers = existingQueuedEvent.targetContainers; + var thenable = suspendedThenable; + suspendedThenable = null; - if ( - targetContainer !== null && - targetContainers.indexOf(targetContainer) === -1 - ) { - targetContainers.push(targetContainer); + { + needsToResetSuspendedThenableDEV = false; } - return existingQueuedEvent; + return thenable; } - -function queueIfContinuousEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - // These set relatedTarget to null because the replayed event will be treated as if we - // moved from outside the window (no target) onto the target once it hydrates. - // Instead of mutating we could clone the event. - switch (domEventName) { - case "focusin": { - var focusEvent = nativeEvent; - queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent( - queuedFocus, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - focusEvent - ); +function checkIfUseWrappedInTryCatch() { + { + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; return true; } + } - case "dragenter": { - var dragEvent = nativeEvent; - queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent( - queuedDrag, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - dragEvent - ); - return true; - } + return false; +} - case "mouseover": { - var mouseEvent = nativeEvent; - queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent( - queuedMouse, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - mouseEvent - ); - return true; - } +var thenableState$1 = null; +var thenableIndexCounter$1 = 0; +var didWarnAboutMaps; +var didWarnAboutGenerators; +var didWarnAboutStringRefs; +var ownerHasKeyUseWarning; +var ownerHasFunctionTypeWarning; - case "pointerover": { - var pointerEvent = nativeEvent; - var pointerId = pointerEvent.pointerId; - queuedPointers.set( - pointerId, - accumulateOrCreateContinuousQueuedReplayableEvent( - queuedPointers.get(pointerId) || null, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - pointerEvent - ) - ); - return true; +var warnForMissingKey = function (child, returnFiber) {}; + +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefs = {}; + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== "object") { + return; } - case "gotpointercapture": { - var _pointerEvent = nativeEvent; - var _pointerId2 = _pointerEvent.pointerId; - queuedPointerCaptures.set( - _pointerId2, - accumulateOrCreateContinuousQueuedReplayableEvent( - queuedPointerCaptures.get(_pointerId2) || null, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - _pointerEvent - ) - ); - return true; + if (!child._store || child._store.validated || child.key != null) { + return; } - } - return false; -} // Check if this target is unblocked. Returns true if it's unblocked. + if (typeof child._store !== "object") { + throw new Error( + "React Component in warnForMissingKey should have a _store. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } // $FlowFixMe unable to narrow type from mixed to writable object -function attemptExplicitHydrationTarget(queuedTarget) { - // TODO: This function shares a lot of logic with findInstanceBlockingEvent. - // Try to unify them. It's a bit tricky since it would require two return - // values. - var targetInst = getClosestInstanceFromNode(queuedTarget.target); + child._store.validated = true; + var componentName = getComponentNameFromFiber(returnFiber) || "Component"; - if (targetInst !== null) { - var nearestMounted = getNearestMountedFiber(targetInst); + if (ownerHasKeyUseWarning[componentName]) { + return; + } - if (nearestMounted !== null) { - var tag = nearestMounted.tag; + ownerHasKeyUseWarning[componentName] = true; - if (tag === SuspenseComponent) { - var instance = getSuspenseInstanceFromFiber(nearestMounted); + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; +} - if (instance !== null) { - // We're blocked on hydrating this boundary. - // Increase its priority. - queuedTarget.blockedOn = instance; - attemptHydrationAtPriority(queuedTarget.priority, function () { - attemptHydrationAtCurrentPriority$1(nearestMounted); - }); - return; - } - } else if (tag === HostRoot) { - var root = nearestMounted.stateNode; +function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; +} - if (isRootDehydrated(root)) { - queuedTarget.blockedOn = getContainerFromFiber(nearestMounted); // We don't currently have a way to increase the priority of - // a root other than sync. +function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - return; - } - } - } + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); } - queuedTarget.blockedOn = null; + return trackUsedThenable(thenableState$1, thenable, index); } -function queueExplicitHydrationTarget(target) { - // TODO: This will read the priority if it's dispatched by the React - // event system but not native events. Should read window.event.type, like - // we do for updates (getCurrentEventPriority). - var updatePriority = getCurrentUpdatePriority(); - var queuedTarget = { - blockedOn: null, - target: target, - priority: updatePriority - }; - var i = 0; +function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; - for (; i < queuedExplicitHydrationTargets.length; i++) { - // Stop once we hit the first target with lower priority than - if ( - !isHigherEventPriority( - updatePriority, - queuedExplicitHydrationTargets[i].priority - ) - ) { - break; - } - } - - queuedExplicitHydrationTargets.splice(i, 0, queuedTarget); - - if (i === 0) { - attemptExplicitHydrationTarget(queuedTarget); - } -} - -function attemptReplayContinuousQueuedEvent(queuedEvent) { - if (queuedEvent.blockedOn !== null) { - return false; - } - - var targetContainers = queuedEvent.targetContainers; - - while (targetContainers.length > 0) { - var targetContainer = targetContainers[0]; - var nextBlockedOn = findInstanceBlockingEvent( - queuedEvent.domEventName, - queuedEvent.eventSystemFlags, - targetContainer, - queuedEvent.nativeEvent - ); + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if ( + // We warn in ReactElement.js if owner and self are equal for string refs + // because these cannot be automatically converted to an arrow function + // using a codemod. Therefore, we don't have to warn about string refs again. + !( + element._owner && + element._self && + element._owner.stateNode !== element._self + ) && // Will already throw with "Function components cannot have string refs" + !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" + !(typeof element.type === "function" && !isReactClass(element.type)) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" + element._owner + ) { + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - if (nextBlockedOn === null) { - if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - var nativeEvent = queuedEvent.nativeEvent; - var nativeEventClone = new nativeEvent.constructor( - nativeEvent.type, - nativeEvent - ); - setReplayingEvent(nativeEventClone); - nativeEvent.target.dispatchEvent(nativeEventClone); - resetReplayingEvent(); - } else { - setReplayingEvent(queuedEvent.nativeEvent); - dispatchEventForPluginEventSystem( - queuedEvent.domEventName, - queuedEvent.eventSystemFlags, - queuedEvent.nativeEvent, - return_targetInst, - targetContainer - ); - resetReplayingEvent(); - } - } else { - // We're still blocked. Try again later. - var fiber = getInstanceFromNode(nextBlockedOn); + if (!didWarnAboutStringRefs[componentName]) { + error( + 'Component "%s" contains the string ref "%s". Support for string refs ' + + "will be removed in a future major release. We recommend using " + + "useRef() or createRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref", + componentName, + mixedRef + ); - if (fiber !== null) { - attemptContinuousHydration$1(fiber); + didWarnAboutStringRefs[componentName] = true; + } } + } - queuedEvent.blockedOn = nextBlockedOn; - return false; - } // This target container was successfully dispatched. Try the next. + if (element._owner) { + var owner = element._owner; + var inst; - targetContainers.shift(); - } + if (owner) { + var ownerFiber = owner; - return true; -} + if (ownerFiber.tag !== ClassComponent) { + throw new Error( + "Function components cannot have string refs. " + + "We recommend using useRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref" + ); + } -function attemptReplayContinuousQueuedEventInMap(queuedEvent, key, map) { - if (attemptReplayContinuousQueuedEvent(queuedEvent)) { - map.delete(key); - } -} + inst = ownerFiber.stateNode; + } -function replayUnblockedEvents() { - hasScheduledReplayAttempt = false; + if (!inst) { + throw new Error( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a " + + "bug in React. Please file an issue." + ); + } // Assigning this to a const so Flow knows it won't change in the closure - if (!enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - // First replay discrete events. - while (queuedDiscreteEvents.length > 0) { - var nextDiscreteEvent = queuedDiscreteEvents[0]; + var resolvedInst = inst; - if (nextDiscreteEvent.blockedOn !== null) { - // We're still blocked. - // Increase the priority of this boundary to unblock - // the next discrete event. - var fiber = getInstanceFromNode(nextDiscreteEvent.blockedOn); + { + checkPropStringCoercion(mixedRef, "ref"); + } - if (fiber !== null) { - attemptDiscreteHydration$1(fiber); - } + var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref - break; + if ( + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef + ) { + return current.ref; } - var targetContainers = nextDiscreteEvent.targetContainers; - - while (targetContainers.length > 0) { - var targetContainer = targetContainers[0]; - var nextBlockedOn = findInstanceBlockingEvent( - nextDiscreteEvent.domEventName, - nextDiscreteEvent.eventSystemFlags, - targetContainer, - nextDiscreteEvent.nativeEvent - ); + var ref = function (value) { + var refs = resolvedInst.refs; - if (nextBlockedOn === null) { - // This whole function is in !enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay, - // so we don't need the new replay behavior code branch. - setReplayingEvent(nextDiscreteEvent.nativeEvent); - dispatchEventForPluginEventSystem( - nextDiscreteEvent.domEventName, - nextDiscreteEvent.eventSystemFlags, - nextDiscreteEvent.nativeEvent, - return_targetInst, - targetContainer - ); - resetReplayingEvent(); + if (value === null) { + delete refs[stringRef]; } else { - // We're still blocked. Try again later. - nextDiscreteEvent.blockedOn = nextBlockedOn; - break; - } // This target container was successfully dispatched. Try the next. + refs[stringRef] = value; + } + }; - targetContainers.shift(); + ref._stringRef = stringRef; + return ref; + } else { + if (typeof mixedRef !== "string") { + throw new Error( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); } - if (nextDiscreteEvent.blockedOn === null) { - // We've successfully replayed the first event. Let's try the next one. - queuedDiscreteEvents.shift(); + if (!element._owner) { + throw new Error( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of" + + " the following reasons:\n" + + "1. You may be adding a ref to a function component\n" + + "2. You may be adding a ref to a component that was not created inside a component's render method\n" + + "3. You have multiple copies of React loaded\n" + + "See https://reactjs.org/link/refs-must-have-owner for more information." + ); } } - } // Next replay any continuous events. - - if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) { - queuedFocus = null; - } - - if (queuedDrag !== null && attemptReplayContinuousQueuedEvent(queuedDrag)) { - queuedDrag = null; - } - - if (queuedMouse !== null && attemptReplayContinuousQueuedEvent(queuedMouse)) { - queuedMouse = null; } - queuedPointers.forEach(attemptReplayContinuousQueuedEventInMap); - queuedPointerCaptures.forEach(attemptReplayContinuousQueuedEventInMap); + return mixedRef; } -function scheduleCallbackIfUnblocked(queuedEvent, unblocked) { - if (queuedEvent.blockedOn === unblocked) { - queuedEvent.blockedOn = null; +function throwOnInvalidObjectType(returnFiber, newChild) { + // $FlowFixMe[method-unbinding] + var childString = Object.prototype.toString.call(newChild); + throw new Error( + "Objects are not valid as a React child (found: " + + (childString === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : childString) + + "). " + + "If you meant to render a collection of children, use an array " + + "instead." + ); +} - if (!hasScheduledReplayAttempt) { - hasScheduledReplayAttempt = true; // Schedule a callback to attempt replaying as many events as are - // now unblocked. This first might not actually be unblocked yet. - // We could check it early to avoid scheduling an unnecessary callback. +function warnOnFunctionType(returnFiber) { + { + var componentName = getComponentNameFromFiber(returnFiber) || "Component"; - Scheduler.unstable_scheduleCallback( - Scheduler.unstable_NormalPriority, - replayUnblockedEvents - ); + if (ownerHasFunctionTypeWarning[componentName]) { + return; } + + ownerHasFunctionTypeWarning[componentName] = true; + + error( + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); } } -function retryIfBlockedOn(unblocked) { - // Mark anything that was blocked on this as no longer blocked - // and eligible for a replay. - if (queuedDiscreteEvents.length > 0) { - scheduleCallbackIfUnblocked(queuedDiscreteEvents[0], unblocked); // This is a exponential search for each boundary that commits. I think it's - // worth it because we expect very few discrete events to queue up and once - // we are actually fully unblocked it will be fast to replay them. +function resolveLazy(lazyType) { + var payload = lazyType._payload; + var init = lazyType._init; + return init(payload); +} // 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. - for (var i = 1; i < queuedDiscreteEvents.length; i++) { - var queuedEvent = queuedDiscreteEvents[i]; +function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } - if (queuedEvent.blockedOn === unblocked) { - queuedEvent.blockedOn = null; - } + var deletions = returnFiber.deletions; + + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); } } - if (queuedFocus !== null) { - scheduleCallbackIfUnblocked(queuedFocus, unblocked); - } + 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. - if (queuedDrag !== null) { - scheduleCallbackIfUnblocked(queuedDrag, unblocked); - } + var childToDelete = currentFirstChild; - if (queuedMouse !== null) { - scheduleCallbackIfUnblocked(queuedMouse, unblocked); - } + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; + } - var unblock = function (queuedEvent) { - return scheduleCallbackIfUnblocked(queuedEvent, unblocked); - }; + return null; + } - queuedPointers.forEach(unblock); - queuedPointerCaptures.forEach(unblock); + 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 + // instead. + var existingChildren = new Map(); + var existingChild = currentFirstChild; - for (var _i = 0; _i < queuedExplicitHydrationTargets.length; _i++) { - var queuedTarget = queuedExplicitHydrationTargets[_i]; + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); + } - if (queuedTarget.blockedOn === unblocked) { - queuedTarget.blockedOn = null; + existingChild = existingChild.sibling; } + + return existingChildren; } - while (queuedExplicitHydrationTargets.length > 0) { - var nextExplicitTarget = queuedExplicitHydrationTargets[0]; + function useFiber(fiber, pendingProps) { + // 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); + clone.index = 0; + clone.sibling = null; + return clone; + } - if (nextExplicitTarget.blockedOn !== null) { - // We're still blocked. - break; - } else { - attemptExplicitHydrationTarget(nextExplicitTarget); + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; - if (nextExplicitTarget.blockedOn === null) { - // We're unblocked. - queuedExplicitHydrationTargets.shift(); - } + if (!shouldTrackSideEffects) { + // During hydration, the useId algorithm needs to know which fibers are + // part of a list of children (arrays, iterators). + newFiber.flags |= Forked; + return lastPlacedIndex; } - } -} -var ReactCurrentBatchConfig$3 = ReactSharedInternals.ReactCurrentBatchConfig; // TODO: can we stop exporting these? + var current = newFiber.alternate; -var _enabled = true; // This is exported in FB builds for use by legacy FB layer infra. -// We'd like to remove this but it's not clear if this is safe. + if (current !== null) { + var oldIndex = current.index; -function setEnabled(enabled) { - _enabled = !!enabled; -} -function isEnabled() { - return _enabled; -} -function createEventListenerWrapperWithPriority( - targetContainer, - domEventName, - eventSystemFlags -) { - var eventPriority = getEventPriority(domEventName); - var listenerWrapper; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } + } - switch (eventPriority) { - case DiscreteEventPriority: - listenerWrapper = dispatchDiscreteEvent; - break; + 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.flags |= Placement | PlacementDEV; + } - case ContinuousEventPriority: - listenerWrapper = dispatchContinuousEvent; - break; + return newFiber; + } - case DefaultEventPriority: - default: - listenerWrapper = dispatchEvent; - break; + function updateTextNode(returnFiber, current, textContent, lanes) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; + return existing; + } } - return listenerWrapper.bind( - null, - domEventName, - eventSystemFlags, - targetContainer - ); -} + function updateElement(returnFiber, current, element, lanes) { + var elementType = element.type; -function dispatchDiscreteEvent( - domEventName, - eventSystemFlags, - container, - nativeEvent -) { - var previousPriority = getCurrentUpdatePriority$1(); - var prevTransition = ReactCurrentBatchConfig$3.transition; - ReactCurrentBatchConfig$3.transition = null; + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); + } - try { - setCurrentUpdatePriority(DiscreteEventPriority); - dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig$3.transition = prevTransition; - } -} + if (current !== null) { + if ( + current.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === current.type) + ) { + // Move based on index + var existing = useFiber(current, element.props); + existing.ref = coerceRef(returnFiber, current, element); + existing.return = returnFiber; -function dispatchContinuousEvent( - domEventName, - eventSystemFlags, - container, - nativeEvent -) { - var previousPriority = getCurrentUpdatePriority$1(); - var prevTransition = ReactCurrentBatchConfig$3.transition; - ReactCurrentBatchConfig$3.transition = null; + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } - try { - setCurrentUpdatePriority(ContinuousEventPriority); - dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig$3.transition = prevTransition; - } -} + return existing; + } + } // Insert -function dispatchEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - if (!_enabled) { - return; + var created = createFiberFromElement(element, returnFiber.mode, lanes); + created.ref = coerceRef(returnFiber, current, element); + created.return = returnFiber; + return created; } - if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - } else { - dispatchEventOriginal( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - } -} - -function dispatchEventOriginal( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - // TODO: replaying capture phase events is currently broken - // because we used to do it during top-level native bubble handlers - // but now we use different bubble and capture handlers. - // In eager mode, we attach capture listeners early, so we need - // to filter them out until we fix the logic to handle them correctly. - var allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0; - - if ( - allowReplay && - hasQueuedDiscreteEvents() && - isDiscreteEventThatRequiresHydration(domEventName) - ) { - // If we already have a queue of discrete events, and this is another discrete - // event, then we can't dispatch it regardless of its target, since they - // need to dispatch in order. - queueDiscreteEvent( - null, // Flags that we're not actually blocked on anything as far as we know. - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - return; - } - - var blockedOn = findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - - if (blockedOn === null) { - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - return_targetInst, - targetContainer - ); - - if (allowReplay) { - clearIfContinuousEvent(domEventName, nativeEvent); + function updatePortal(returnFiber, current, portal, lanes) { + if ( + current === null || + current.tag !== HostPortal || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, portal.children || []); + existing.return = returnFiber; + return existing; } - - return; } - if (allowReplay) { - if (isDiscreteEventThatRequiresHydration(domEventName)) { - // This to be replayed later once the target is available. - queueDiscreteEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent + function updateFragment(returnFiber, current, fragment, lanes, key) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + lanes, + key ); - return; + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; + return existing; } + } + function createChild(returnFiber, newChild, lanes) { if ( - queueIfContinuousEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ) + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" ) { - return; - } // We need to clear only if we didn't queue because - // queueing is accumulative. + // 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, lanes); + created.return = returnFiber; + return created; + } - clearIfContinuousEvent(domEventName, nativeEvent); - } // This is not replayable so we'll invoke it but without a target, - // in case the event system needs to trace it. + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + lanes + ); - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - null, - targetContainer - ); -} + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; + } -function dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - var blockedOn = findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + lanes + ); - if (blockedOn === null) { - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - return_targetInst, - targetContainer - ); - clearIfContinuousEvent(domEventName, nativeEvent); - return; - } + _created2.return = returnFiber; + return _created2; + } - if ( - queueIfContinuousEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ) - ) { - nativeEvent.stopPropagation(); - return; - } // We need to clear only if we didn't queue because - // queueing is accumulative. + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes); + } + } - clearIfContinuousEvent(domEventName, nativeEvent); + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - if ( - eventSystemFlags & IS_CAPTURE_PHASE && - isDiscreteEventThatRequiresHydration(domEventName) - ) { - while (blockedOn !== null) { - var fiber = getInstanceFromNode(blockedOn); + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (fiber !== null) { - attemptSynchronousHydration$1(fiber); + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); } - var nextBlockedOn = findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - - if (nextBlockedOn === null) { - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - return_targetInst, - targetContainer + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes ); } - if (nextBlockedOn === blockedOn) { - break; - } - - blockedOn = nextBlockedOn; + throwOnInvalidObjectType(returnFiber, newChild); } - if (blockedOn !== null) { - nativeEvent.stopPropagation(); + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } } - return; - } // This is not replayable so we'll invoke it but without a target, - // in case the event system needs to trace it. + return null; + } - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - null, - targetContainer - ); -} + function updateSlot(returnFiber, oldFiber, newChild, lanes) { + // Update the fiber if the keys match, otherwise return null. + var key = oldFiber !== null ? oldFiber.key : null; -var return_targetInst = null; // Returns a SuspenseInstance or Container if it's blocked. -// The return_targetInst field above is conceptually part of the return value. + if ( + (typeof newChild === "string" && newChild !== "") || + 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; + } -function findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - // TODO: Warn if _enabled is false. - return_targetInst = null; - var nativeEventTarget = getEventTarget(nativeEvent); - var targetInst = getClosestInstanceFromNode(nativeEventTarget); + return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); + } - if (targetInst !== null) { - var nearestMounted = getNearestMountedFiber(targetInst); + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - if (nearestMounted === null) { - // This tree has been unmounted already. Dispatch without a target. - targetInst = null; - } else { - var tag = nearestMounted.tag; + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - if (tag === SuspenseComponent) { - var instance = getSuspenseInstanceFromFiber(nearestMounted); + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes); + } + } - if (instance !== null) { - // Queue the event to be replayed later. Abort dispatching since we - // don't want this event dispatched twice through the event system. - // TODO: If this is the first discrete event in the queue. Schedule an increased - // priority for this boundary. - return instance; - } // This shouldn't happen, something went wrong but to avoid blocking - // the whole system, dispatch the event without a target. - // TODO: Warn. + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } - targetInst = null; - } else if (tag === HostRoot) { - var root = nearestMounted.stateNode; + return updateFragment(returnFiber, oldFiber, newChild, lanes, null); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (isRootDehydrated(root)) { - // If this happens during a replay something went wrong and it might block - // the whole system. - return getContainerFromFiber(nearestMounted); - } + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateSlot( + returnFiber, + oldFiber, + unwrapThenable(thenable), + lanes + ); + } - targetInst = null; - } else if (nearestMounted !== targetInst) { - // If we get an event (ex: img onload) before committing that - // component's mount, ignore it for now (that is, treat it as if it was an - // event on a non-React tree). We might also consider queueing events and - // dispatching them after the mount. - targetInst = null; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return updateSlot( + returnFiber, + oldFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); } + + throwOnInvalidObjectType(returnFiber, newChild); } - } - return_targetInst = targetInst; // We're not blocked on anything. + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } - return null; -} -function getEventPriority(domEventName) { - switch (domEventName) { - // Used by SimpleEventPlugin: - case "cancel": - case "click": - case "close": - case "contextmenu": - case "copy": - case "cut": - case "auxclick": - case "dblclick": - case "dragend": - case "dragstart": - case "drop": - case "focusin": - case "focusout": - case "input": - case "invalid": - case "keydown": - case "keypress": - case "keyup": - case "mousedown": - case "mouseup": - case "paste": - case "pause": - case "play": - case "pointercancel": - case "pointerdown": - case "pointerup": - case "ratechange": - case "reset": - case "resize": - case "seeked": - case "submit": - case "touchcancel": - case "touchend": - case "touchstart": - case "volumechange": // Used by polyfills: - // eslint-disable-next-line no-fallthrough + return null; + } - case "change": - case "selectionchange": - case "textInput": - case "compositionstart": - case "compositionend": - case "compositionupdate": // Only enableCreateEventHandleAPI: - // eslint-disable-next-line no-fallthrough + function updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChild, + lanes + ) { + if ( + (typeof newChild === "string" && newChild !== "") || + 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, lanes); + } - case "beforeblur": - case "afterblur": // Not used by React but could be by user code: - // eslint-disable-next-line no-fallthrough + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _matchedFiber = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; - case "beforeinput": - case "blur": - case "fullscreenchange": - case "focus": - case "hashchange": - case "popstate": - case "select": - case "selectstart": - return DiscreteEventPriority; + return updateElement(returnFiber, _matchedFiber, newChild, lanes); + } - case "drag": - case "dragenter": - case "dragexit": - case "dragleave": - case "dragover": - case "mousemove": - case "mouseout": - case "mouseover": - case "pointermove": - case "pointerout": - case "pointerover": - case "scroll": - case "toggle": - case "touchmove": - case "wheel": // Not used by React but could be by user code: - // eslint-disable-next-line no-fallthrough + case REACT_PORTAL_TYPE: { + var _matchedFiber2 = + existingChildren.get( + newChild.key === null ? newIdx : newChild.key + ) || null; - case "mouseenter": - case "mouseleave": - case "pointerenter": - case "pointerleave": - return ContinuousEventPriority; + return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); + } - case "message": { - // We might be in the Scheduler callback. - // Eventually this mechanism will be replaced by a check - // of the current priority on the native scheduler. - var schedulerPriority = getCurrentPriorityLevel(); - - switch (schedulerPriority) { - case ImmediatePriority: - return DiscreteEventPriority; - - case UserBlockingPriority: - return ContinuousEventPriority; + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + init(payload), + lanes + ); + } - case NormalPriority$1: - case LowPriority: - // TODO: Handle LowSchedulerPriority, somehow. Maybe the same lane as hydration. - return DefaultEventPriority; + if (isArray(newChild) || getIteratorFn(newChild)) { + var _matchedFiber3 = existingChildren.get(newIdx) || null; - case IdlePriority: - return IdleEventPriority; + return updateFragment( + returnFiber, + _matchedFiber3, + newChild, + lanes, + null + ); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - default: - return DefaultEventPriority; + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + unwrapThenable(thenable), + lanes + ); } - } - default: - return DefaultEventPriority; - } -} + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return updateFromMap( + existingChildren, + returnFiber, + newIdx, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } -var loggedTypeFailures = {}; -var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + throwOnInvalidObjectType(returnFiber, newChild); + } -function setCurrentlyValidatingElement(element) { - { - if (element) { - var owner = element._owner; - var stack = describeUnknownElementTypeFrameInDEV( - element.type, - element._source, - owner ? owner.type : null - ); - ReactDebugCurrentFrame.setExtraStackFrame(stack); - } else { - ReactDebugCurrentFrame.setExtraStackFrame(null); + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } } + + return null; } -} + /** + * Warns if there is a duplicate or missing key + */ -function checkPropTypes(typeSpecs, values, location, componentName, element) { - { - // $FlowFixMe This is okay but Flow doesn't know it. - var has = Function.call.bind(hasOwnProperty); + function warnOnInvalidKey(child, knownKeys, returnFiber) { + { + if (typeof child !== "object" || child === null) { + return knownKeys; + } - for (var typeSpecName in typeSpecs) { - if (has(typeSpecs, typeSpecName)) { - var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to - // fail the render phase where it didn't fail before. So we log it. - // After these have been cleaned up, we'll let them throw. + switch (child.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + warnForMissingKey(child, returnFiber); + var key = child.key; - try { - // This is intentionally an invariant that gets caught. It's the same - // behavior as without this statement except with a better message. - if (typeof typeSpecs[typeSpecName] !== "function") { - // eslint-disable-next-line react-internal/prod-error-codes - var err = Error( - (componentName || "React class") + - ": " + - location + - " type `" + - typeSpecName + - "` is invalid; " + - "it must be a function, usually from the `prop-types` package, but received `" + - typeof typeSpecs[typeSpecName] + - "`." + - "This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`." - ); - err.name = "Invariant Violation"; - throw err; + if (typeof key !== "string") { + break; } - error$1 = typeSpecs[typeSpecName]( - values, - typeSpecName, - componentName, - location, - null, - "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED" - ); - } catch (ex) { - error$1 = ex; - } + if (knownKeys === null) { + knownKeys = new Set(); + knownKeys.add(key); + break; + } - if (error$1 && !(error$1 instanceof Error)) { - setCurrentlyValidatingElement(element); + if (!knownKeys.has(key)) { + knownKeys.add(key); + break; + } error( - "%s: type specification of %s" + - " `%s` is invalid; the type checker " + - "function must return `null` or an `Error` but returned a %s. " + - "You may have forgotten to pass an argument to the type checker " + - "creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and " + - "shape all require an argument).", - componentName || "React class", - location, - typeSpecName, - typeof error$1 + "Encountered two children with the same key, `%s`. " + + "Keys should be unique so that components maintain their identity " + + "across updates. Non-unique keys may cause children to be " + + "duplicated and/or omitted — the behavior is unsupported and " + + "could change in a future version.", + key ); - setCurrentlyValidatingElement(null); - } - - if ( - error$1 instanceof Error && - !(error$1.message in loggedTypeFailures) - ) { - // Only monitor this failure once because there tends to be a lot of the - // same error. - loggedTypeFailures[error$1.message] = true; - setCurrentlyValidatingElement(element); - - error("Failed %s type: %s", location, error$1.message); + break; - setCurrentlyValidatingElement(null); - } + case REACT_LAZY_TYPE: + var payload = child._payload; + var init = child._init; + warnOnInvalidKey(init(payload), knownKeys, returnFiber); + break; } } + + return knownKeys; } -} -var warnedAboutMissingGetChildContext; + function reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChildren, + lanes + ) { + // 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. + { + // First, validate keys. + var knownKeys = null; -{ - warnedAboutMissingGetChildContext = {}; -} + for (var i = 0; i < newChildren.length; i++) { + var child = newChildren[i]; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } -var emptyContextObject = {}; + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; -{ - Object.freeze(emptyContextObject); -} // A cursor to the current merged context object on the stack. + for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } -var contextStackCursor = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed. + var newFiber = updateSlot( + returnFiber, + oldFiber, + newChildren[newIdx], + lanes + ); -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. + 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; + } -var previousContext = emptyContextObject; + break; + } -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; - } + 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); + } + } - return contextStackCursor.current; - } -} + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); -function cacheContext(workInProgress, unmaskedContext, maskedContext) { - { - var instance = workInProgress.stateNode; - instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; - instance.__reactInternalMemoizedMaskedChildContext = maskedContext; - } -} + 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; + } -function getMaskedContext(workInProgress, unmaskedContext) { - { - var type = workInProgress.type; - var contextTypes = type.contextTypes; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } - 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. + if (newIdx === newChildren.length) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); - var instance = workInProgress.stateNode; + if (getIsHydrating()) { + var numberOfForks = newIdx; + pushTreeFork(returnFiber, numberOfForks); + } - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext - ) { - return instance.__reactInternalMemoizedMaskedChildContext; + return resultingFirstChild; } - var context = {}; - - for (var key in contextTypes) { - context[key] = unmaskedContext[key]; - } + 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], lanes); - { - var name = getComponentNameFromFiber(workInProgress) || "Unknown"; - checkPropTypes(contextTypes, context, "context", name); - } // Cache unmasked context so we can avoid recreating masked context unless necessary. - // Context is created before the class component is instantiated so check for instance. + if (_newFiber === null) { + continue; + } - if (instance) { - cacheContext(workInProgress, unmaskedContext, context); - } + lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); - return context; - } -} + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber; + } else { + previousNewFiber.sibling = _newFiber; + } -function hasContextChanged() { - { - return didPerformWorkStackCursor.current; - } -} + previousNewFiber = _newFiber; + } -function isContextProvider(type) { - { - var childContextTypes = type.childContextTypes; - return childContextTypes !== null && childContextTypes !== undefined; - } -} + if (getIsHydrating()) { + var _numberOfForks = newIdx; + pushTreeFork(returnFiber, _numberOfForks); + } -function popContext(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - } -} + return resultingFirstChild; + } // Add all children to a key map for quick lookups. -function popTopLevelContextObject(fiber) { - { - pop(didPerformWorkStackCursor, fiber); - pop(contextStackCursor, fiber); - } -} + var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. -function pushTopLevelContextObject(fiber, context, didChange) { - { - if (contextStackCursor.current !== emptyContextObject) { - throw new Error( - "Unexpected context found on stack. " + - "This error is likely caused by a bug in React. Please file an issue." + for (; newIdx < newChildren.length; newIdx++) { + var _newFiber2 = updateFromMap( + existingChildren, + returnFiber, + newIdx, + newChildren[newIdx], + lanes ); - } - - 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") { - { - var componentName = getComponentNameFromFiber(fiber) || "Unknown"; + if (_newFiber2 !== null) { + 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 + ); + } + } - if (!warnedAboutMissingGetChildContext[componentName]) { - warnedAboutMissingGetChildContext[componentName] = true; + lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); - error( - "%s.childContextTypes is specified but there is no getChildContext() method " + - "on the instance. You can either define getChildContext() on %s or remove " + - "childContextTypes from it.", - componentName, - componentName - ); + if (previousNewFiber === null) { + resultingFirstChild = _newFiber2; + } else { + previousNewFiber.sibling = _newFiber2; } - } - return parentContext; + previousNewFiber = _newFiber2; + } } - var childContext = instance.getChildContext(); - - for (var contextKey in childContext) { - if (!(contextKey in childContextTypes)) { - throw new Error( - (getComponentNameFromFiber(fiber) || "Unknown") + - '.getChildContext(): key "' + - contextKey + - '" is not defined in childContextTypes.' - ); - } + 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); + }); } - { - var name = getComponentNameFromFiber(fiber) || "Unknown"; - checkPropTypes(childContextTypes, childContext, "child context", name); + if (getIsHydrating()) { + var _numberOfForks2 = newIdx; + pushTreeFork(returnFiber, _numberOfForks2); } - return assign({}, parentContext, childContext); + return resultingFirstChild; } -} -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. + function reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChildrenIterable, + lanes + ) { + // This is the same implementation as reconcileChildrenArray(), + // but using the iterator instead. + var iteratorFn = getIteratorFn(newChildrenIterable); - 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. + if (typeof iteratorFn !== "function") { + throw new Error( + "An object is not an iterable. This error is likely caused by a bug in " + + "React. Please file an issue." + ); + } - previousContext = contextStackCursor.current; - push(contextStackCursor, memoizedMergedChildContext, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return true; - } -} + { + // We don't support rendering Generators because it's a mutation. + // See https://github.com/facebook/react/issues/12995 + if ( + typeof Symbol === "function" && // $FlowFixMe Flow doesn't know about toStringTag + newChildrenIterable[Symbol.toStringTag] === "Generator" + ) { + if (!didWarnAboutGenerators) { + error( + "Using Generators as children is unsupported and will likely yield " + + "unexpected results because enumerating a generator mutates it. " + + "You may convert it to an array with `Array.from()` or the " + + "`[...spread]` operator before rendering. Keep in mind " + + "you might need to polyfill these features for older browsers." + ); + } -function invalidateContextProvider(workInProgress, type, didChange) { - { - var instance = workInProgress.stateNode; + didWarnAboutGenerators = true; + } // Warn about using Maps as children - if (!instance) { - throw new Error( - "Expected to have an instance by this point. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } + if (newChildrenIterable.entries === iteratorFn) { + if (!didWarnAboutMaps) { + error( + "Using Maps as children is not supported. " + + "Use an array of keyed ReactElements instead." + ); + } - 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. + didWarnAboutMaps = true; + } // First, validate keys. + // We'll get a different iterator later for the main pass. - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); // Now push the new context and mark that it has changed. + var _newChildren = iteratorFn.call(newChildrenIterable); - push(contextStackCursor, mergedContext, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); - } else { - pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); + if (_newChildren) { + var knownKeys = null; + + var _step = _newChildren.next(); + + for (; !_step.done; _step = _newChildren.next()) { + var child = _step.value; + knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + } + } } - } -} -function findCurrentUnmaskedContext(fiber) { - { - // Currently this is only used with renderSubtreeIntoContainer; not sure if it - // makes sense elsewhere - if (!isFiberMounted(fiber) || fiber.tag !== ClassComponent) { - throw new Error( - "Expected subtree parent to be a mounted class component. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + var newChildren = iteratorFn.call(newChildrenIterable); + + if (newChildren == null) { + throw new Error("An iterable object provided no iterator."); } - var node = fiber; + var resultingFirstChild = null; + var previousNewFiber = null; + var oldFiber = currentFirstChild; + var lastPlacedIndex = 0; + var newIdx = 0; + var nextOldFiber = null; + var step = newChildren.next(); - do { - switch (node.tag) { - case HostRoot: - return node.stateNode.context; + for ( + ; + oldFiber !== null && !step.done; + newIdx++, step = newChildren.next() + ) { + if (oldFiber.index > newIdx) { + nextOldFiber = oldFiber; + oldFiber = null; + } else { + nextOldFiber = oldFiber.sibling; + } - case ClassComponent: { - var Component = node.type; + var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes); - if (isContextProvider(Component)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } + 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; + 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); } - } // $FlowFixMe[incompatible-type] we bail out when we get a null + } - node = node.return; - } while (node !== null); + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); - throw new Error( - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } -} + 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; + } -var LegacyRoot = 0; -var ConcurrentRoot = 1; + previousNewFiber = newFiber; + oldFiber = nextOldFiber; + } -// We use the existence of the state object as an indicator that the component -// is hidden. -var OffscreenVisible = - /* */ - 1; -var OffscreenDetached = - /* */ - 2; -var OffscreenPassiveEffectsConnected = - /* */ - 4; -function isOffscreenManual(offscreenFiber) { - return ( - offscreenFiber.memoizedProps !== null && - offscreenFiber.memoizedProps.mode === "manual" - ); -} + if (step.done) { + // We've reached the end of the new children. We can delete the rest. + deleteRemainingChildren(returnFiber, oldFiber); -var syncQueue = null; -var includesLegacySyncCallbacks = false; -var isFlushingSyncQueue = false; -function scheduleSyncCallback(callback) { - // Push this callback into an internal queue. We'll flush these either in - // the next tick, or earlier if something calls `flushSyncCallbackQueue`. - if (syncQueue === null) { - syncQueue = [callback]; - } else { - // Push onto existing queue. Don't need to schedule a callback because - // we already scheduled one when we created the queue. - syncQueue.push(callback); - } -} -function scheduleLegacySyncCallback(callback) { - includesLegacySyncCallbacks = true; - scheduleSyncCallback(callback); -} -function flushSyncCallbacksOnlyInLegacyMode() { - // Only flushes the queue if there's a legacy sync callback scheduled. - // TODO: There's only a single type of callback: performSyncOnWorkOnRoot. So - // it might make more sense for the queue to be a list of roots instead of a - // list of generic callbacks. Then we can have two: one for legacy roots, one - // for concurrent roots. And this method would only flush the legacy ones. - if (includesLegacySyncCallbacks) { - flushSyncCallbacks(); - } -} -function flushSyncCallbacks() { - if (!isFlushingSyncQueue && syncQueue !== null) { - // Prevent re-entrance. - isFlushingSyncQueue = true; // Set the event priority to discrete - // TODO: Is this necessary anymore? The only user code that runs in this - // queue is in the render or commit phases, which already set the - // event priority. Should be able to remove. + if (getIsHydrating()) { + var numberOfForks = newIdx; + pushTreeFork(returnFiber, numberOfForks); + } - var previousUpdatePriority = getCurrentUpdatePriority$1(); - setCurrentUpdatePriority(DiscreteEventPriority); - var errors = null; - var queue = syncQueue; // $FlowFixMe[incompatible-use] found when upgrading Flow + return resultingFirstChild; + } - for (var i = 0; i < queue.length; i++) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - var callback = queue[i]; + 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, lanes); - try { - do { - var isSync = true; // $FlowFixMe[incompatible-type] we bail out when we get a null + if (_newFiber3 === null) { + continue; + } - callback = callback(isSync); - } while (callback !== null); - } catch (error) { - // Collect errors so we can rethrow them at the end - if (errors === null) { - errors = [error]; + lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + // TODO: Move out of the loop. This only happens for the first run. + resultingFirstChild = _newFiber3; } else { - errors.push(error); + previousNewFiber.sibling = _newFiber3; } + + previousNewFiber = _newFiber3; } - } - syncQueue = null; - includesLegacySyncCallbacks = false; - setCurrentUpdatePriority(previousUpdatePriority); - isFlushingSyncQueue = false; + if (getIsHydrating()) { + var _numberOfForks3 = newIdx; + pushTreeFork(returnFiber, _numberOfForks3); + } - if (errors !== null) { - if (errors.length > 1) { - if (typeof AggregateError === "function") { - // eslint-disable-next-line no-undef - throw new AggregateError(errors); - } else { - for (var _i = 1; _i < errors.length; _i++) { - scheduleCallback$2( - ImmediatePriority, - throwError.bind(null, errors[_i]) + 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, + lanes + ); + + 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 ); } + } - var firstError = errors[0]; - throw firstError; + lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + + if (previousNewFiber === null) { + resultingFirstChild = _newFiber4; + } else { + previousNewFiber.sibling = _newFiber4; } - } else { - var error = errors[0]; - throw error; + + previousNewFiber = _newFiber4; } } - } - - return null; -} -function throwError(error) { - throw error; -} + 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); + }); + } -var nativeConsole = console; -var nativeConsoleLog = null; -var pendingGroupArgs = []; -var printedGroupIndex = -1; + if (getIsHydrating()) { + var _numberOfForks4 = newIdx; + pushTreeFork(returnFiber, _numberOfForks4); + } -function formatLanes(laneOrLanes) { - return "0b" + laneOrLanes.toString(2).padStart(31, "0"); -} + return resultingFirstChild; + } -function group() { - for ( - var _len = arguments.length, groupArgs = new Array(_len), _key = 0; - _key < _len; - _key++ + function reconcileSingleTextNode( + returnFiber, + currentFirstChild, + textContent, + lanes ) { - groupArgs[_key] = arguments[_key]; + // 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); + 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, lanes); + created.return = returnFiber; + return created; } - pendingGroupArgs.push(groupArgs); + function reconcileSingleElement( + returnFiber, + currentFirstChild, + element, + lanes + ) { + var key = element.key; + var child = currentFirstChild; - if (nativeConsoleLog === null) { - nativeConsoleLog = nativeConsole.log; - nativeConsole.log = log; - } -} + 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) { + var elementType = element.type; -function groupEnd() { - pendingGroupArgs.pop(); + if (elementType === REACT_FRAGMENT_TYPE) { + if (child.tag === Fragment) { + deleteRemainingChildren(returnFiber, child.sibling); + var existing = useFiber(child, element.props.children); + existing.return = returnFiber; - while (printedGroupIndex >= pendingGroupArgs.length) { - nativeConsole.groupEnd(); - printedGroupIndex--; - } + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } - if (pendingGroupArgs.length === 0) { - nativeConsole.log = nativeConsoleLog; - nativeConsoleLog = null; - } -} + return existing; + } + } else { + if ( + child.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === child.type) + ) { + deleteRemainingChildren(returnFiber, child.sibling); -function log() { - if (printedGroupIndex < pendingGroupArgs.length - 1) { - for (var i = printedGroupIndex + 1; i < pendingGroupArgs.length; i++) { - var groupArgs = pendingGroupArgs[i]; - nativeConsole.group.apply(nativeConsole, groupArgs); - } + var _existing = useFiber(child, element.props); - printedGroupIndex = pendingGroupArgs.length - 1; - } + _existing.ref = coerceRef(returnFiber, child, element); + _existing.return = returnFiber; - if (typeof nativeConsoleLog === "function") { - nativeConsoleLog.apply(void 0, arguments); - } else { - nativeConsole.log.apply(nativeConsole, arguments); - } -} + { + _existing._debugSource = element._source; + _existing._debugOwner = element._owner; + } -var REACT_LOGO_STYLE = - "background-color: #20232a; color: #61dafb; padding: 0 2px;"; -function logCommitStarted(lanes) { - { - if (enableDebugTracing) { - group( - "%c\u269B\uFE0F%c commit%c (" + formatLanes(lanes) + ")", - REACT_LOGO_STYLE, - "", - "font-weight: normal;" - ); - } - } -} -function logCommitStopped() { - { - if (enableDebugTracing) { - groupEnd(); + return _existing; + } + } // Didn't match. + + deleteRemainingChildren(returnFiber, child); + break; + } else { + deleteChild(returnFiber, child); + } + + child = child.sibling; } - } -} -var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; // $FlowFixMe: Flow cannot handle polymorphic WeakMaps -var wakeableIDs = new PossiblyWeakMap$1(); -var wakeableID = 0; + if (element.type === REACT_FRAGMENT_TYPE) { + var created = createFiberFromFragment( + element.props.children, + returnFiber.mode, + lanes, + element.key + ); + created.return = returnFiber; + return created; + } else { + var _created4 = createFiberFromElement(element, returnFiber.mode, lanes); -function getWakeableID(wakeable) { - if (!wakeableIDs.has(wakeable)) { - wakeableIDs.set(wakeable, wakeableID++); + _created4.ref = coerceRef(returnFiber, currentFirstChild, element); + _created4.return = returnFiber; + return _created4; + } } - return wakeableIDs.get(wakeable); -} + function reconcileSinglePortal( + returnFiber, + currentFirstChild, + portal, + lanes + ) { + var key = portal.key; + var child = currentFirstChild; -function logComponentSuspended(componentName, wakeable) { - { - if (enableDebugTracing) { - var id = getWakeableID(wakeable); - var display = wakeable.displayName || wakeable; - log( - "%c\u269B\uFE0F%c " + componentName + " suspended", - REACT_LOGO_STYLE, - "color: #80366d; font-weight: bold;", - id, - display - ); - wakeable.then( - function () { - log( - "%c\u269B\uFE0F%c " + componentName + " resolved", - REACT_LOGO_STYLE, - "color: #80366d; font-weight: bold;", - id, - display - ); - }, - function () { - log( - "%c\u269B\uFE0F%c " + componentName + " rejected", - REACT_LOGO_STYLE, - "color: #80366d; font-weight: bold;", - id, - display - ); + 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 || []); + existing.return = returnFiber; + return existing; + } else { + deleteRemainingChildren(returnFiber, child); + break; } - ); - } - } -} -function logLayoutEffectsStarted(lanes) { - { - if (enableDebugTracing) { - group( - "%c\u269B\uFE0F%c layout effects%c (" + formatLanes(lanes) + ")", - REACT_LOGO_STYLE, - "", - "font-weight: normal;" - ); - } - } -} -function logLayoutEffectsStopped() { - { - if (enableDebugTracing) { - groupEnd(); - } - } -} -function logPassiveEffectsStarted(lanes) { - { - if (enableDebugTracing) { - group( - "%c\u269B\uFE0F%c passive effects%c (" + formatLanes(lanes) + ")", - REACT_LOGO_STYLE, - "", - "font-weight: normal;" - ); - } - } -} -function logPassiveEffectsStopped() { - { - if (enableDebugTracing) { - groupEnd(); - } - } -} -function logRenderStarted(lanes) { - { - if (enableDebugTracing) { - group( - "%c\u269B\uFE0F%c render%c (" + formatLanes(lanes) + ")", - REACT_LOGO_STYLE, - "", - "font-weight: normal;" - ); - } - } -} -function logRenderStopped() { - { - if (enableDebugTracing) { - groupEnd(); - } - } -} -function logForceUpdateScheduled(componentName, lane) { - { - if (enableDebugTracing) { - log( - "%c\u269B\uFE0F%c " + - componentName + - " forced update %c(" + - formatLanes(lane) + - ")", - REACT_LOGO_STYLE, - "color: #db2e1f; font-weight: bold;", - "" - ); - } - } -} -function logStateUpdateScheduled(componentName, lane, payloadOrAction) { - { - if (enableDebugTracing) { - log( - "%c\u269B\uFE0F%c " + - componentName + - " updated state %c(" + - formatLanes(lane) + - ")", - REACT_LOGO_STYLE, - "color: #01a252; font-weight: bold;", - "", - payloadOrAction - ); + } else { + deleteChild(returnFiber, child); + } + + child = child.sibling; } - } -} -// Intentionally not using it yet to derisk the initial implementation, because -// the way we push/pop these values is a bit unusual. If there's a mistake, I'd -// rather the ids be wrong than crash the whole reconciler. + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + 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. -var forkStack = []; -var forkStackIndex = 0; -var treeForkProvider = null; -var treeForkCount = 0; -var idStack = []; -var idStackIndex = 0; -var treeContextProvider = null; -var treeContextId = 1; -var treeContextOverflow = ""; -function isForkedChild(workInProgress) { - warnIfNotHydrating(); - return (workInProgress.flags & Forked) !== NoFlags$1; -} -function getForksAtLevel(workInProgress) { - warnIfNotHydrating(); - return treeForkCount; -} -function getTreeId() { - var overflow = treeContextOverflow; - var idWithLeadingBit = treeContextId; - var id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit); - return id.toString(32) + overflow; -} -function pushTreeFork(workInProgress, totalChildren) { - // This is called right after we reconcile an array (or iterator) of child - // fibers, because that's the only place where we know how many children in - // the whole set without doing extra work later, or storing addtional - // information on the fiber. - // - // That's why this function is separate from pushTreeId — it's called during - // the render phase of the fork parent, not the child, which is where we push - // the other context values. - // - // In the Fizz implementation this is much simpler because the child is - // rendered in the same callstack as the parent. - // - // It might be better to just add a `forks` field to the Fiber type. It would - // make this module simpler. - warnIfNotHydrating(); - forkStack[forkStackIndex++] = treeForkCount; - forkStack[forkStackIndex++] = treeForkProvider; - treeForkProvider = workInProgress; - treeForkCount = totalChildren; -} -function pushTreeId(workInProgress, totalChildren, index) { - warnIfNotHydrating(); - idStack[idStackIndex++] = treeContextId; - idStack[idStackIndex++] = treeContextOverflow; - idStack[idStackIndex++] = treeContextProvider; - treeContextProvider = workInProgress; - var baseIdWithLeadingBit = treeContextId; - var baseOverflow = treeContextOverflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part - // of the id; we use it to account for leading 0s. + function reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + // 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. + // TODO: Let's use recursion like we do for Usable nodes? + var isUnkeyedTopLevelFragment = + typeof newChild === "object" && + newChild !== null && + newChild.type === REACT_FRAGMENT_TYPE && + newChild.key === null; - var baseLength = getBitLength(baseIdWithLeadingBit) - 1; - var baseId = baseIdWithLeadingBit & ~(1 << baseLength); - var slot = index + 1; - var length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into - // consideration the leading 1 we use to mark the end of the sequence. + if (isUnkeyedTopLevelFragment) { + newChild = newChild.props.children; + } // Handle object types - if (length > 30) { - // We overflowed the bitwise-safe range. Fall back to slower algorithm. - // This branch assumes the length of the base id is greater than 5; it won't - // work for smaller ids, because you need 5 bits per character. - // - // We encode the id in multiple steps: first the base id, then the - // remaining digits. - // - // Each 5 bit sequence corresponds to a single base 32 character. So for - // example, if the current id is 23 bits long, we can convert 20 of those - // bits into a string of 4 characters, with 3 bits left over. - // - // First calculate how many bits in the base id represent a complete - // sequence of characters. - var numberOfOverflowBits = baseLength - (baseLength % 5); // Then create a bitmask that selects only those bits. + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: + return placeSingleChild( + reconcileSingleElement( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - var newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string. + case REACT_PORTAL_TYPE: + return placeSingleChild( + reconcileSinglePortal( + returnFiber, + currentFirstChild, + newChild, + lanes + ) + ); - var newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id. + case REACT_LAZY_TYPE: + var payload = newChild._payload; + var init = newChild._init; // TODO: This function is supposed to be non-recursive. - var restOfBaseId = baseId >> numberOfOverflowBits; - var restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because - // we made more room, this time it won't overflow. + return reconcileChildFibers( + returnFiber, + currentFirstChild, + init(payload), + lanes + ); + } - var restOfLength = getBitLength(totalChildren) + restOfBaseLength; - var restOfNewBits = slot << restOfBaseLength; - var id = restOfNewBits | restOfBaseId; - var overflow = newOverflow + baseOverflow; - treeContextId = (1 << restOfLength) | id; - treeContextOverflow = overflow; - } else { - // Normal path - var newBits = slot << baseLength; + if (isArray(newChild)) { + return reconcileChildrenArray( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + } - var _id = newBits | baseId; + if (getIteratorFn(newChild)) { + return reconcileChildrenIterator( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + } // Usables are a valid React node type. When React encounters a Usable in + // a child position, it unwraps it using the same algorithm as `use`. For + // example, for promises, React will throw an exception to unwind the + // stack, then replay the component once the promise resolves. + // + // A difference from `use` is that React will keep unwrapping the value + // until it reaches a non-Usable type. + // + // e.g. Usable>> should resolve to T + // + // The structure is a bit unfortunate. Ideally, we shouldn't need to + // replay the entire begin phase of the parent fiber in order to reconcile + // the children again. This would require a somewhat significant refactor, + // because reconcilation happens deep within the begin phase, and + // depending on the type of work, not always at the end. We should + // consider as an future improvement. - var _overflow = baseOverflow; - treeContextId = (1 << length) | _id; - treeContextOverflow = _overflow; - } -} -function pushMaterializedTreeId(workInProgress) { - warnIfNotHydrating(); // This component materialized an id. This will affect any ids that appear - // in its children. + if (typeof newChild.then === "function") { + var thenable = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + unwrapThenable(thenable), + lanes + ); + } - var returnFiber = workInProgress.return; + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } - if (returnFiber !== null) { - var numberOfForks = 1; - var slotIndex = 0; - pushTreeFork(workInProgress, numberOfForks); - pushTreeId(workInProgress, numberOfForks, slotIndex); - } -} + throwOnInvalidObjectType(returnFiber, newChild); + } -function getBitLength(number) { - return 32 - clz32(number); -} + if ( + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" + ) { + return placeSingleChild( + reconcileSingleTextNode( + returnFiber, + currentFirstChild, + "" + newChild, + lanes + ) + ); + } -function getLeadingBit(id) { - return 1 << (getBitLength(id) - 1); -} + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } // Remaining cases are all treated as empty. -function popTreeContext(workInProgress) { - // Restore the previous values. - // This is a bit more complicated than other context-like modules in Fiber - // because the same Fiber may appear on the stack multiple times and for - // different reasons. We have to keep popping until the work-in-progress is - // no longer at the top of the stack. - while (workInProgress === treeForkProvider) { - treeForkProvider = forkStack[--forkStackIndex]; - forkStack[forkStackIndex] = null; - treeForkCount = forkStack[--forkStackIndex]; - forkStack[forkStackIndex] = null; + return deleteRemainingChildren(returnFiber, currentFirstChild); } - while (workInProgress === treeContextProvider) { - treeContextProvider = idStack[--idStackIndex]; - idStack[idStackIndex] = null; - treeContextOverflow = idStack[--idStackIndex]; - idStack[idStackIndex] = null; - treeContextId = idStack[--idStackIndex]; - idStack[idStackIndex] = null; - } -} -function getSuspendedTreeContext() { - warnIfNotHydrating(); + function reconcileChildFibers( + returnFiber, + currentFirstChild, + newChild, + lanes + ) { + // This indirection only exists so we can reset `thenableState` at the end. + // It should get inlined by Closure. + thenableIndexCounter$1 = 0; + var firstChildFiber = reconcileChildFibersImpl( + returnFiber, + currentFirstChild, + newChild, + lanes + ); + thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets + // set at the beginning. - if (treeContextProvider !== null) { - return { - id: treeContextId, - overflow: treeContextOverflow - }; - } else { - return null; + return firstChildFiber; } -} -function restoreSuspendedTreeContext(workInProgress, suspendedContext) { - warnIfNotHydrating(); - idStack[idStackIndex++] = treeContextId; - idStack[idStackIndex++] = treeContextOverflow; - idStack[idStackIndex++] = treeContextProvider; - treeContextId = suspendedContext.id; - treeContextOverflow = suspendedContext.overflow; - treeContextProvider = workInProgress; + + return reconcileChildFibers; } -function warnIfNotHydrating() { - { - if (!getIsHydrating()) { - error( - "Expected to be hydrating. This is a bug in React. Please file " + - "an issue." - ); - } - } +var reconcileChildFibers = createChildReconciler(true); +var mountChildFibers = createChildReconciler(false); +function resetChildReconcilerOnUnwind() { + // On unwind, clear any pending thenables that were used. + thenableState$1 = null; + thenableIndexCounter$1 = 0; } +function cloneChildFibers(current, workInProgress) { + if (current !== null && workInProgress.child !== current.child) { + throw new Error("Resuming work not yet implemented."); + } -// This may have been an insertion or a hydration. + if (workInProgress.child === null) { + return; + } -var hydrationParentFiber = null; -var nextHydratableInstance = null; -var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches -// due to earlier mismatches or a suspended fiber. + var currentChild = workInProgress.child; + var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); + workInProgress.child = newChild; + newChild.return = workInProgress; -var didSuspendOrErrorDEV = false; // Hydration errors that were thrown inside this boundary + while (currentChild.sibling !== null) { + currentChild = currentChild.sibling; + newChild = newChild.sibling = createWorkInProgress( + currentChild, + currentChild.pendingProps + ); + newChild.return = workInProgress; + } -var hydrationErrors = null; -var rootOrSingletonContext = false; + newChild.sibling = null; +} // Reset a workInProgress child set to prepare it for a second pass. -function warnIfHydrating() { - { - if (isHydrating) { - error( - "We should not be hydrating here. This is a bug in React. Please file a bug." - ); - } - } -} +function resetChildFibers(workInProgress, lanes) { + var child = workInProgress.child; -function markDidThrowWhileHydratingDEV() { - { - didSuspendOrErrorDEV = true; - } -} -function didSuspendOrErrorWhileHydratingDEV() { - { - return didSuspendOrErrorDEV; + while (child !== null) { + resetWorkInProgress(child, lanes); + child = child.sibling; } } -function enterHydrationState(fiber) { - var parentInstance = fiber.stateNode.containerInfo; - nextHydratableInstance = - getFirstHydratableChildWithinContainer(parentInstance); - hydrationParentFiber = fiber; - isHydrating = true; - hydrationErrors = null; - didSuspendOrErrorDEV = false; - rootOrSingletonContext = true; - return true; -} +// TODO: This isn't being used yet, but it's intended to replace the +// InvisibleParentContext that is currently managed by SuspenseContext. -function reenterHydrationStateFromDehydratedSuspenseInstance( - fiber, - suspenseInstance, - treeContext -) { - nextHydratableInstance = - getFirstHydratableChildWithinSuspenseInstance(suspenseInstance); - hydrationParentFiber = fiber; - isHydrating = true; - hydrationErrors = null; - didSuspendOrErrorDEV = false; - rootOrSingletonContext = false; +var currentTreeHiddenStackCursor = createCursor(null); +var prevRenderLanesStackCursor = createCursor(NoLanes); +function pushHiddenContext(fiber, context) { + var prevRenderLanes = getRenderLanes(); + push(prevRenderLanesStackCursor, prevRenderLanes, fiber); + push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all + // lanes that would have rendered if the hidden subtree hadn't been deferred. + // That is, in order to reveal content from hidden -> visible, we must commit + // all the updates that we skipped when we originally hid the tree. - if (treeContext !== null) { - restoreSuspendedTreeContext(fiber, treeContext); - } + setRenderLanes(mergeLanes(prevRenderLanes, context.baseLanes)); +} +function reuseHiddenContextOnStack(fiber) { + // This subtree is not currently hidden, so we don't need to add any lanes + // to the render lanes. But we still need to push something to avoid a + // context mismatch. Reuse the existing context on the stack. + push(prevRenderLanesStackCursor, getRenderLanes(), fiber); + push( + currentTreeHiddenStackCursor, + currentTreeHiddenStackCursor.current, + fiber + ); +} +function popHiddenContext(fiber) { + // Restore the previous render lanes from the stack + setRenderLanes(prevRenderLanesStackCursor.current); + pop(currentTreeHiddenStackCursor, fiber); + pop(prevRenderLanesStackCursor, fiber); +} +function isCurrentTreeHidden() { + return currentTreeHiddenStackCursor.current !== null; +} - return true; +// suspends, i.e. it's the nearest `catch` block on the stack. + +var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. +// Everything above this is the "shell". When this is null, it means we're +// rendering in the shell of the app. If it's non-null, it means we're rendering +// deeper than the shell, inside a new tree that wasn't already visible. +// +// The main way we use this concept is to determine whether showing a fallback +// would result in a desirable or undesirable loading state. Activing a fallback +// in the shell is considered an undersirable loading state, because it would +// mean hiding visible (albeit stale) content in the current tree — we prefer to +// show the stale content, rather than switch to a fallback. But showing a +// fallback in a new tree is fine, because there's no stale content to +// prefer instead. + +var shellBoundary = null; +function getShellBoundary() { + return shellBoundary; } +function pushPrimaryTreeSuspenseHandler(handler) { + // TODO: Pass as argument + var current = handler.alternate; + var props = handler.pendingProps; // Experimental feature: Some Suspense boundaries are marked as having an + // undesirable fallback state. These have special behavior where we only + // activate the fallback if there's no other boundary on the stack that we can + // use instead. -function warnUnhydratedInstance(returnFiber, instance) { - { - switch (returnFiber.tag) { - case HostRoot: { - didNotHydrateInstanceWithinContainer( - returnFiber.stateNode.containerInfo, - instance - ); - break; - } + if ( + props.unstable_avoidThisFallback === true && // If an avoided boundary is already visible, it behaves identically to + // a regular Suspense boundary. + (current === null || isCurrentTreeHidden()) + ) { + if (shellBoundary === null) { + // We're rendering in the shell. There's no parent Suspense boundary that + // can provide a desirable fallback state. We'll use this boundary. + push(suspenseHandlerStackCursor, handler, handler); // However, because this is not a desirable fallback, the children are + // still considered part of the shell. So we intentionally don't assign + // to `shellBoundary`. + } else { + // There's already a parent Suspense boundary that can provide a desirable + // fallback state. Prefer that one. + var handlerOnStack = suspenseHandlerStackCursor.current; + push(suspenseHandlerStackCursor, handlerOnStack, handler); + } - case HostSingleton: - case HostComponent: { - var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode; - didNotHydrateInstance( - returnFiber.type, - returnFiber.memoizedProps, - returnFiber.stateNode, - instance, // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode - ); - break; - } + return; + } // TODO: If the parent Suspense handler already suspended, there's no reason + // to push a nested Suspense handler, because it will get replaced by the + // outer fallback, anyway. Consider this as a future optimization. - case SuspenseComponent: { - var suspenseState = returnFiber.memoizedState; - if (suspenseState.dehydrated !== null) - didNotHydrateInstanceWithinSuspenseInstance( - suspenseState.dehydrated, - instance - ); - break; + push(suspenseHandlerStackCursor, handler, handler); + + if (shellBoundary === null) { + if (current === null || isCurrentTreeHidden()) { + // This boundary is not visible in the current UI. + shellBoundary = handler; + } else { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This boundary is showing a fallback in the current UI. + shellBoundary = handler; } } } } +function pushFallbackTreeSuspenseHandler(fiber) { + // We're about to render the fallback. If something in the fallback suspends, + // it's akin to throwing inside of a `catch` block. This boundary should not + // capture. Reuse the existing handler on the stack. + reuseSuspenseHandlerOnStack(fiber); +} +function pushOffscreenSuspenseHandler(fiber) { + if (fiber.tag === OffscreenComponent) { + push(suspenseHandlerStackCursor, fiber, fiber); -function deleteHydratableInstance(returnFiber, instance) { - warnUnhydratedInstance(returnFiber, instance); - var childToDelete = createFiberFromHostInstanceForDeletion(); - childToDelete.stateNode = instance; - childToDelete.return = returnFiber; - var deletions = returnFiber.deletions; + if (shellBoundary !== null); + else { + var current = fiber.alternate; - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; + if (current !== null) { + var prevState = current.memoizedState; + + if (prevState !== null) { + // This is the first boundary in the stack that's already showing + // a fallback. So everything outside is considered the shell. + shellBoundary = fiber; + } + } + } } else { - deletions.push(childToDelete); + // This is a LegacyHidden component. + reuseSuspenseHandlerOnStack(fiber); } } +function reuseSuspenseHandlerOnStack(fiber) { + push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); +} +function getSuspenseHandler() { + return suspenseHandlerStackCursor.current; +} +function popSuspenseHandler(fiber) { + pop(suspenseHandlerStackCursor, fiber); -function warnNonhydratedInstance(returnFiber, fiber) { - { - if (didSuspendOrErrorDEV) { - // Inside a boundary that already suspended. We're currently rendering the - // siblings of a suspended node. The mismatch may be due to the missing - // data, so it's probably a false positive. - return; - } - - switch (returnFiber.tag) { - case HostRoot: { - var parentContainer = returnFiber.stateNode.containerInfo; - - switch (fiber.tag) { - case HostSingleton: - case HostComponent: - var type = fiber.type; - didNotFindHydratableInstanceWithinContainer(parentContainer, type); - break; + if (shellBoundary === fiber) { + // Popping back into the shell. + shellBoundary = null; + } +} // SuspenseList context +// TODO: Move to a separate module? We may change the SuspenseList +// implementation to hide/show in the commit phase, anyway. - case HostText: - var text = fiber.pendingProps; - didNotFindHydratableTextInstanceWithinContainer( - parentContainer, - text - ); - break; - } +var DefaultSuspenseContext = 0; +var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added +// items into their fallback state during one of the render passes. - break; - } +var ForceSuspenseFallback = 2; +var suspenseStackCursor = createCursor(DefaultSuspenseContext); +function hasSuspenseListContext(parentContext, flag) { + return (parentContext & flag) !== 0; +} +function setDefaultShallowSuspenseListContext(parentContext) { + return parentContext & SubtreeSuspenseContextMask; +} +function setShallowSuspenseListContext(parentContext, shallowContext) { + return (parentContext & SubtreeSuspenseContextMask) | shallowContext; +} +function pushSuspenseListContext(fiber, newContext) { + push(suspenseStackCursor, newContext, fiber); +} +function popSuspenseListContext(fiber) { + pop(suspenseStackCursor, fiber); +} - case HostSingleton: - case HostComponent: { - var parentType = returnFiber.type; - var parentProps = returnFiber.memoizedProps; - var parentInstance = returnFiber.stateNode; +// A non-null SuspenseState means that it is blocked for one reason or another. +// - A non-null dehydrated field means it's blocked pending hydration. +// - A non-null dehydrated field can use isSuspenseInstancePending or +// isSuspenseInstanceFallback to query the reason for being dehydrated. +// - A null dehydrated field means it's blocked by something suspending and +// we're currently showing a fallback instead. - switch (fiber.tag) { - case HostSingleton: - case HostComponent: { - var _type = fiber.type; - var _props = fiber.pendingProps; - var isConcurrentMode = - (returnFiber.mode & ConcurrentMode) !== NoMode; - didNotFindHydratableInstance( - parentType, - parentProps, - parentInstance, - _type, - _props, // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode - ); - break; - } +function findFirstSuspended(row) { + var node = row; - case HostText: { - var _text = fiber.pendingProps; + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - var _isConcurrentMode = - (returnFiber.mode & ConcurrentMode) !== NoMode; + if (state !== null) { + var dehydrated = state.dehydrated; - didNotFindHydratableTextInstance( - parentType, - parentProps, - parentInstance, - _text, // TODO: Delete this argument when we remove the legacy root API. - _isConcurrentMode - ); - break; - } + if ( + dehydrated === null || + isSuspenseInstancePending(dehydrated) || + isSuspenseInstanceFallback(dehydrated) + ) { + return node; } - - break; } + } else if ( + node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't + // keep track of whether it suspended or not. + node.memoizedProps.revealOrder !== undefined + ) { + var didSuspend = (node.flags & DidCapture) !== NoFlags$1; - case SuspenseComponent: { - var suspenseState = returnFiber.memoizedState; - var _parentInstance = suspenseState.dehydrated; - if (_parentInstance !== null) - switch (fiber.tag) { - case HostSingleton: - case HostComponent: - var _type2 = fiber.type; - didNotFindHydratableInstanceWithinSuspenseInstance( - _parentInstance, - _type2 - ); - break; - - case HostText: - var _text2 = fiber.pendingProps; - didNotFindHydratableTextInstanceWithinSuspenseInstance( - _parentInstance, - _text2 - ); - break; - } - break; + if (didSuspend) { + return node; } + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } - default: - return; + if (node === row) { + return null; } - } -} -function insertNonHydratedInstance(returnFiber, fiber) { - fiber.flags = (fiber.flags & ~Hydrating) | Placement; - warnNonhydratedInstance(returnFiber, fiber); -} + while (node.sibling === null) { + if (node.return === null || node.return === row) { + return null; + } -function tryHydrateInstance(fiber, nextInstance) { - // fiber is a HostComponent Fiber - var instance = canHydrateInstance(nextInstance, fiber.type); + node = node.return; + } - if (instance !== null) { - fiber.stateNode = instance; - hydrationParentFiber = fiber; - nextHydratableInstance = getFirstHydratableChild(instance); - rootOrSingletonContext = false; - return true; + node.sibling.return = node.return; + node = node.sibling; } - return false; + return null; } -function tryHydrateText(fiber, nextInstance) { - // fiber is a HostText Fiber - var text = fiber.pendingProps; - var textInstance = canHydrateTextInstance(nextInstance, text); +var NoFlags = + /* */ + 0; // Represents whether effect should fire. - if (textInstance !== null) { - fiber.stateNode = textInstance; - hydrationParentFiber = fiber; // Text Instances don't have children so there's nothing to hydrate. +var HasEffect = + /* */ + 1; // Represents the phase in which the effect (not the clean-up) fires. - nextHydratableInstance = null; - return true; - } +var Insertion = + /* */ + 2; +var Layout = + /* */ + 4; +var Passive = + /* */ + 8; - return false; -} +// and should be reset before starting a new render. +// This tracks which mutable sources need to be reset after a render. -function tryHydrateSuspense(fiber, nextInstance) { - // fiber is a SuspenseComponent Fiber - var suspenseInstance = canHydrateSuspenseInstance(nextInstance); +var workInProgressSources = []; +var rendererSigil$1; - if (suspenseInstance !== null) { - var suspenseState = { - dehydrated: suspenseInstance, - treeContext: getSuspendedTreeContext(), - retryLane: OffscreenLane - }; - fiber.memoizedState = suspenseState; // Store the dehydrated fragment as a child fiber. - // This simplifies the code for getHostSibling and deleting nodes, - // since it doesn't have to consider all Suspense boundaries and - // check if they're dehydrated ones or not. +{ + // Used to detect multiple renderers using the same mutable source. + rendererSigil$1 = {}; +} - var dehydratedFragment = - createFiberFromDehydratedFragment(suspenseInstance); - dehydratedFragment.return = fiber; - fiber.child = dehydratedFragment; - hydrationParentFiber = fiber; // While a Suspense Instance does have children, we won't step into - // it during the first pass. Instead, we'll reenter it later. +function markSourceAsDirty(mutableSource) { + workInProgressSources.push(mutableSource); +} +function resetWorkInProgressVersions() { + for (var i = 0; i < workInProgressSources.length; i++) { + var mutableSource = workInProgressSources[i]; - nextHydratableInstance = null; - return true; + { + mutableSource._workInProgressVersionPrimary = null; + } } - return false; + workInProgressSources.length = 0; } - -function shouldClientRenderOnMismatch(fiber) { - return ( - (fiber.mode & ConcurrentMode) !== NoMode && - (fiber.flags & DidCapture) === NoFlags$1 - ); +function getWorkInProgressVersion(mutableSource) { + { + return mutableSource._workInProgressVersionPrimary; + } } +function setWorkInProgressVersion(mutableSource, version) { + { + mutableSource._workInProgressVersionPrimary = version; + } -function throwOnHydrationMismatch(fiber) { - throw new Error( - "Hydration failed because the initial UI does not match what was " + - "rendered on the server." - ); + workInProgressSources.push(mutableSource); } - -function claimHydratableSingleton(fiber) { +function warnAboutMultipleRenderersDEV(mutableSource) { { - if (!isHydrating) { - return; + { + if (mutableSource._currentPrimaryRenderer == null) { + mutableSource._currentPrimaryRenderer = rendererSigil$1; + } else if (mutableSource._currentPrimaryRenderer !== rendererSigil$1) { + error( + "Detected multiple renderers concurrently rendering the " + + "same mutable source. This is currently unsupported." + ); + } } - - var currentRootContainer = getRootHostContainer(); - var currentHostContext = getHostContext(); - var instance = (fiber.stateNode = resolveSingletonInstance( - fiber.type, - fiber.pendingProps, - currentRootContainer, - currentHostContext, - false - )); - hydrationParentFiber = fiber; - rootOrSingletonContext = true; - nextHydratableInstance = getFirstHydratableChild(instance); - } -} - -function advanceToFirstAttemptableInstance(fiber) { - // fiber is HostComponent Fiber - while ( - nextHydratableInstance && - shouldSkipHydratableForInstance( - nextHydratableInstance, - fiber.type, - fiber.pendingProps - ) - ) { - // Flow doesn't understand that inside this block nextHydratableInstance is not null - var instance = nextHydratableInstance; - nextHydratableInstance = getNextHydratableSibling(instance); } -} +} // Eager reads the version of a mutable source and stores it on the root. +// This ensures that the version used for server rendering matches the one +// that is eventually read during hydration. +// If they don't match there's a potential tear and a full deopt render is required. -function advanceToFirstAttemptableTextInstance() { - while ( - nextHydratableInstance && - shouldSkipHydratableForTextInstance(nextHydratableInstance) - ) { - // Flow doesn't understand that inside this block nextHydratableInstance is not null - var instance = nextHydratableInstance; - nextHydratableInstance = getNextHydratableSibling(instance); - } -} +function registerMutableSourceForHydration(root, mutableSource) { + var getVersion = mutableSource._getVersion; + var version = getVersion(mutableSource._source); // TODO Clear this data once all pending hydration work is finished. + // Retaining it forever may interfere with GC. -function advanceToFirstAttemptableSuspenseInstance() { - while ( - nextHydratableInstance && - shouldSkipHydratableForSuspenseInstance(nextHydratableInstance) - ) { - // Flow doesn't understand that inside this block nextHydratableInstance is not null - var instance = nextHydratableInstance; - nextHydratableInstance = getNextHydratableSibling(instance); + if (root.mutableSourceEagerHydrationData == null) { + root.mutableSourceEagerHydrationData = [mutableSource, version]; + } else { + root.mutableSourceEagerHydrationData.push(mutableSource, version); } } -function tryToClaimNextHydratableInstance(fiber) { - if (!isHydrating) { - return; - } - - { - if (!isHydratableType(fiber.type, fiber.pendingProps)) { - // This fiber never hydrates from the DOM and always does an insert - fiber.flags = (fiber.flags & ~Hydrating) | Placement; - isHydrating = false; - hydrationParentFiber = fiber; - return; - } - } - - var initialInstance = nextHydratableInstance; - - if (rootOrSingletonContext) { - // We may need to skip past certain nodes in these contexts - advanceToFirstAttemptableInstance(fiber); - } - - var nextInstance = nextHydratableInstance; - - if (!nextInstance) { - if (shouldClientRenderOnMismatch(fiber)) { - warnNonhydratedInstance(hydrationParentFiber, fiber); - throwOnHydrationMismatch(); - } // Nothing to hydrate. Make it an insertion. - - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - - var firstAttemptedInstance = nextInstance; - - if (!tryHydrateInstance(fiber, nextInstance)) { - if (shouldClientRenderOnMismatch(fiber)) { - warnNonhydratedInstance(hydrationParentFiber, fiber); - throwOnHydrationMismatch(); - } // 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. +var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentBatchConfig$3 = ReactSharedInternals.ReactCurrentBatchConfig; +var didWarnAboutMismatchedHooksForComponent; +var didWarnUncachedGetSnapshot; +var didWarnAboutUseWrappedInTryCatch; - nextHydratableInstance = getNextHydratableSibling(nextInstance); - var prevHydrationParentFiber = hydrationParentFiber; +{ + didWarnAboutMismatchedHooksForComponent = new Set(); + didWarnAboutUseWrappedInTryCatch = new Set(); +} // These are set right before calling the component. - if (rootOrSingletonContext) { - // We may need to skip past certain nodes in these contexts - advanceToFirstAttemptableInstance(fiber); - } +var renderLanes$1 = NoLanes; // The work-in-progress fiber. I've named it differently to distinguish it from +// the work-in-progress hook. - if ( - !nextHydratableInstance || - !tryHydrateInstance(fiber, nextHydratableInstance) - ) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - 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. +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. - deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); - } -} +var currentHook = null; +var workInProgressHook = null; // Whether an update was scheduled at any point during the render phase. This +// does not get reset if we do another render pass; only when we're completely +// finished evaluating this component. This is an optimization so we know +// whether we need to clear render phase updates after a throw. -function tryToClaimNextHydratableTextInstance(fiber) { - if (!isHydrating) { - return; - } +var didScheduleRenderPhaseUpdate = false; // Where an update was scheduled only during the current render pass. This +// gets reset after each attempt. +// TODO: Maybe there's some way to consolidate this with +// `didScheduleRenderPhaseUpdate`. Or with `numberOfReRenders`. - var text = fiber.pendingProps; - var isHydratable = isHydratableText(text); - var initialInstance = nextHydratableInstance; +var didScheduleRenderPhaseUpdateDuringThisPass = false; +var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. - if (rootOrSingletonContext && isHydratable) { - // We may need to skip past certain nodes in these contexts. - // We don't skip if the text is not hydratable because we know no hydratables - // exist which could match this Fiber - advanceToFirstAttemptableTextInstance(); - } +var localIdCounter = 0; // Counts number of `use`-d thenables - var nextInstance = nextHydratableInstance; +var thenableIndexCounter = 0; +var thenableState = null; // Used for ids that are generated completely client-side (i.e. not during +// hydration). This counter is global, so client ids are not stable across +// render attempts. - if (!nextInstance || !isHydratable) { - // We exclude non hydrabable text because we know there are no matching hydratables. - // We either throw or insert depending on the render mode. - if (shouldClientRenderOnMismatch(fiber)) { - warnNonhydratedInstance(hydrationParentFiber, fiber); - throwOnHydrationMismatch(); - } // Nothing to hydrate. Make it an insertion. +var globalClientIdCounter = 0; +var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } +var currentHookNameInDev = null; // In DEV, this list ensures that hooks are called in the same order between renders. +// The list stores the order of hooks used during the initial render (mount). +// Subsequent renders (updates) reference this list. - var firstAttemptedInstance = nextInstance; +var hookTypesDev = null; +var hookTypesUpdateIndexDev = -1; // In DEV, this tracks whether currently rendering component needs to ignore +// the dependencies for Hooks that need them (e.g. useEffect or useMemo). +// When true, such Hooks will always be "remounted". Only used during hot reload. - if (!tryHydrateText(fiber, nextInstance)) { - if (shouldClientRenderOnMismatch(fiber)) { - warnNonhydratedInstance(hydrationParentFiber, fiber); - throwOnHydrationMismatch(); - } // 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. +var ignorePreviousDependencies = false; - nextHydratableInstance = getNextHydratableSibling(nextInstance); - var prevHydrationParentFiber = hydrationParentFiber; +function mountHookTypesDev() { + { + var hookName = currentHookNameInDev; - if (rootOrSingletonContext && isHydratable) { - // We may need to skip past certain nodes in these contexts - advanceToFirstAttemptableTextInstance(); + if (hookTypesDev === null) { + hookTypesDev = [hookName]; + } else { + hookTypesDev.push(hookName); } - - if ( - !nextHydratableInstance || - !tryHydrateText(fiber, nextHydratableInstance) - ) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - 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(prevHydrationParentFiber, firstAttemptedInstance); } } -function tryToClaimNextHydratableSuspenseInstance(fiber) { - if (!isHydrating) { - return; - } - - var initialInstance = nextHydratableInstance; - - if (rootOrSingletonContext) { - // We may need to skip past certain nodes in these contexts - advanceToFirstAttemptableSuspenseInstance(); - } - - var nextInstance = nextHydratableInstance; - - if (!nextInstance) { - if (shouldClientRenderOnMismatch(fiber)) { - warnNonhydratedInstance(hydrationParentFiber, fiber); - throwOnHydrationMismatch(); - } // Nothing to hydrate. Make it an insertion. - - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - return; - } - - var firstAttemptedInstance = nextInstance; - - if (!tryHydrateSuspense(fiber, nextInstance)) { - if (shouldClientRenderOnMismatch(fiber)) { - warnNonhydratedInstance(hydrationParentFiber, fiber); - throwOnHydrationMismatch(); - } // 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. +function updateHookTypesDev() { + { + var hookName = currentHookNameInDev; - nextHydratableInstance = getNextHydratableSibling(nextInstance); - var prevHydrationParentFiber = hydrationParentFiber; + if (hookTypesDev !== null) { + hookTypesUpdateIndexDev++; - if (rootOrSingletonContext) { - // We may need to skip past certain nodes in these contexts - advanceToFirstAttemptableSuspenseInstance(); + if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { + warnOnHookMismatchInDev(hookName); + } } - - if ( - !nextHydratableInstance || - !tryHydrateSuspense(fiber, nextHydratableInstance) - ) { - // Nothing to hydrate. Make it an insertion. - insertNonHydratedInstance(hydrationParentFiber, fiber); - isHydrating = false; - hydrationParentFiber = fiber; - nextHydratableInstance = initialInstance; - 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(prevHydrationParentFiber, firstAttemptedInstance); } } -function prepareToHydrateHostInstance(fiber, hostContext) { - var instance = fiber.stateNode; - var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV; - var updatePayload = hydrateInstance( - instance, - fiber.type, - fiber.memoizedProps, - hostContext, - fiber, - shouldWarnIfMismatchDev - ); // 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; +function checkDepsAreArrayDev(deps) { + { + if (deps !== undefined && deps !== null && !isArray(deps)) { + // Verify deps, but only on mount to avoid extra checks. + // It's unlikely their type would change as usually you define them inline. + error( + "%s received a final argument that is not an array (instead, received `%s`). When " + + "specified, the final argument must be an array.", + currentHookNameInDev, + typeof deps + ); + } } - - return false; } -function prepareToHydrateHostTextInstance(fiber) { - var textInstance = fiber.stateNode; - var textContent = fiber.memoizedProps; - var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV; - var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); +function warnOnHookMismatchInDev(currentHookName) { + { + var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - if (shouldUpdate) { - // We assume that prepareToHydrateHostTextInstance is called in a context where the - // hydration parent is the parent host component of this host text. - var returnFiber = hydrationParentFiber; + if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { + didWarnAboutMismatchedHooksForComponent.add(componentName); - if (returnFiber !== null) { - switch (returnFiber.tag) { - case HostRoot: { - var parentContainer = returnFiber.stateNode.containerInfo; - var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode; - didNotMatchHydratedContainerTextInstance( - parentContainer, - textInstance, - textContent, // TODO: Delete this argument when we remove the legacy root API. - isConcurrentMode, - shouldWarnIfMismatchDev - ); - break; - } + if (hookTypesDev !== null) { + var table = ""; + var secondColumnStart = 30; - case HostSingleton: - case HostComponent: { - var parentType = returnFiber.type; - var parentProps = returnFiber.memoizedProps; - var parentInstance = returnFiber.stateNode; + for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { + var oldHookName = hookTypesDev[i]; + var newHookName = + i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; + var row = i + 1 + ". " + oldHookName; // Extra space so second column lines up + // lol @ IE not supporting String#repeat - var _isConcurrentMode2 = - (returnFiber.mode & ConcurrentMode) !== NoMode; + while (row.length < secondColumnStart) { + row += " "; + } - didNotMatchHydratedTextInstance( - parentType, - parentProps, - parentInstance, - textInstance, - textContent, // TODO: Delete this argument when we remove the legacy root API. - _isConcurrentMode2, - shouldWarnIfMismatchDev - ); - break; + row += newHookName + "\n"; + table += row; } + + error( + "React has detected a change in the order of Hooks called by %s. " + + "This will lead to bugs and errors if not fixed. " + + "For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks\n\n" + + " Previous render Next render\n" + + " ------------------------------------------------------\n" + + "%s" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + componentName, + table + ); } } } - - return shouldUpdate; -} - -function prepareToHydrateHostSuspenseInstance(fiber) { - var suspenseState = fiber.memoizedState; - var suspenseInstance = - suspenseState !== null ? suspenseState.dehydrated : null; - - if (!suspenseInstance) { - throw new Error( - "Expected to have a hydrated suspense instance. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } - - hydrateSuspenseInstance(suspenseInstance, fiber); } -function skipPastDehydratedSuspenseInstance(fiber) { - var suspenseState = fiber.memoizedState; - var suspenseInstance = - suspenseState !== null ? suspenseState.dehydrated : null; - - if (!suspenseInstance) { - throw new Error( - "Expected to have a hydrated suspense instance. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } - - return getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); +function throwInvalidHookError() { + throw new Error( + "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for" + + " one of the following reasons:\n" + + "1. You might have mismatching versions of React and the renderer (such as React DOM)\n" + + "2. You might be breaking the Rules of Hooks\n" + + "3. You might have more than one copy of React in the same app\n" + + "See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem." + ); } -function popToNextHostParent(fiber) { - hydrationParentFiber = fiber.return; - - while (hydrationParentFiber) { - switch (hydrationParentFiber.tag) { - case HostRoot: - case HostSingleton: - rootOrSingletonContext = true; - return; - - case HostComponent: - case SuspenseComponent: - rootOrSingletonContext = false; - return; - - default: - hydrationParentFiber = hydrationParentFiber.return; +function areHookInputsEqual(nextDeps, prevDeps) { + { + if (ignorePreviousDependencies) { + // Only true when this component is being hot reloaded. + return false; } } -} -function popHydrationState(fiber) { - if (fiber !== hydrationParentFiber) { - // We're deeper than the current hydration context, inside an inserted - // tree. - return false; - } + if (prevDeps === null) { + { + error( + "%s received a final argument during this render, but not during " + + "the previous render. Even though the final argument is optional, " + + "its type cannot change between renders.", + currentHookNameInDev + ); + } - 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 shouldClear = false; - { - // With float we never clear the Root, or Singleton instances. We also do not clear Instances - // that have singleton text content - if ( - fiber.tag !== HostRoot && - fiber.tag !== HostSingleton && - !( - fiber.tag === HostComponent && - shouldSetTextContent(fiber.type, fiber.memoizedProps) - ) - ) { - shouldClear = true; + // Don't bother comparing lengths in prod because these arrays should be + // passed inline. + if (nextDeps.length !== prevDeps.length) { + error( + "The final argument passed to %s changed size between renders. The " + + "order and size of this array must remain constant.\n\n" + + "Previous: %s\n" + + "Incoming: %s", + currentHookNameInDev, + "[" + prevDeps.join(", ") + "]", + "[" + nextDeps.join(", ") + "]" + ); } - } - - if (shouldClear) { - var nextInstance = nextHydratableInstance; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (nextInstance) { - if (shouldClientRenderOnMismatch(fiber)) { - warnIfUnhydratedTailNodes(fiber); - throwOnHydrationMismatch(); - } else { - while (nextInstance) { - deleteHydratableInstance(fiber, nextInstance); - nextInstance = getNextHydratableSibling(nextInstance); - } - } + for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (objectIs(nextDeps[i], prevDeps[i])) { + continue; } - } - popToNextHostParent(fiber); - - if (fiber.tag === SuspenseComponent) { - nextHydratableInstance = skipPastDehydratedSuspenseInstance(fiber); - } else { - nextHydratableInstance = hydrationParentFiber - ? getNextHydratableSibling(fiber.stateNode) - : null; + return false; } return true; } -function hasUnhydratedTailNodes() { - return isHydrating && nextHydratableInstance !== null; -} +function renderWithHooks( + current, + workInProgress, + Component, + props, + secondArg, + nextRenderLanes +) { + renderLanes$1 = nextRenderLanes; + currentlyRenderingFiber$1 = workInProgress; -function warnIfUnhydratedTailNodes(fiber) { - var nextInstance = nextHydratableInstance; + { + hookTypesDev = current !== null ? current._debugHookTypes : null; + hookTypesUpdateIndexDev = -1; // Used for hot reloading: - while (nextInstance) { - warnUnhydratedInstance(fiber, nextInstance); - nextInstance = getNextHydratableSibling(nextInstance); + ignorePreviousDependencies = + current !== null && current.type !== workInProgress.type; } -} - -function resetHydrationState() { - hydrationParentFiber = null; - nextHydratableInstance = null; - isHydrating = false; - didSuspendOrErrorDEV = false; -} -function upgradeHydrationErrorsToRecoverable() { - if (hydrationErrors !== null) { - // Successfully completed a forced client render. The errors that occurred - // during the hydration attempt are now recovered. We will log them in - // commit phase, once the entire tree has finished. - queueRecoverableErrors(hydrationErrors); - hydrationErrors = null; + workInProgress.memoizedState = null; + workInProgress.updateQueue = null; + workInProgress.lanes = NoLanes; // The following should have already been reset + // currentHook = null; + // workInProgressHook = null; + // didScheduleRenderPhaseUpdate = false; + // localIdCounter = 0; + // thenableIndexCounter = 0; + // thenableState = null; + // TODO Warn if no hooks are used at all during mount, then some are used during update. + // Currently we will identify the update render as a mount because memoizedState === null. + // This is tricky because it's valid for certain types of components (e.g. React.lazy) + // Using memoizedState to differentiate between mount/update only works if at least one stateful hook is used. + // Non-stateful hooks (e.g. context) don't get added to memoizedState, + // so memoizedState would be null during updates and mounts. + + { + if (current !== null && current.memoizedState !== null) { + ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; + } else if (hookTypesDev !== null) { + // This dispatcher handles an edge case where a component is updating, + // but no stateful hooks have been used. + // We want to match the production code behavior (which will use HooksDispatcherOnMount), + // but with the extra DEV validation to ensure hooks ordering hasn't changed. + // This dispatcher does that. + ReactCurrentDispatcher$1.current = + HooksDispatcherOnMountWithHookTypesInDEV; + } else { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + } + } // In Strict Mode, during development, user functions are double invoked to + // help detect side effects. The logic for how this is implemented for in + // hook components is a bit complex so let's break it down. + // + // We will invoke the entire component function twice. However, during the + // second invocation of the component, the hook state from the first + // invocation will be reused. That means things like `useMemo` functions won't + // run again, because the deps will match and the memoized result will + // be reused. + // + // We want memoized functions to run twice, too, so account for this, user + // functions are double invoked during the *first* invocation of the component + // function, and are *not* double invoked during the second incovation: + // + // - First execution of component function: user functions are double invoked + // - Second execution of component function (in Strict Mode, during + // development): user functions are not double invoked. + // + // This is intentional for a few reasons; most importantly, it's because of + // how `use` works when something suspends: it reuses the promise that was + // passed during the first attempt. This is itself a form of memoization. + // We need to be able to memoize the reactive inputs to the `use` call using + // a hook (i.e. `useMemo`), which means, the reactive inputs to `use` must + // come from the same component invocation as the output. + // + // There are plenty of tests to ensure this behavior is correct. + + var shouldDoubleRenderDEV = + (workInProgress.mode & StrictLegacyMode) !== NoMode; + shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; + var children = Component(props, secondArg); + shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update + + if (didScheduleRenderPhaseUpdateDuringThisPass) { + // Keep rendering until the component stabilizes (there are no more render + // phase updates). + children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg + ); } -} -function getIsHydrating() { - return isHydrating; -} + if (shouldDoubleRenderDEV) { + // In development, components are invoked twice to help detect side effects. + setIsStrictModeForDevtools(true); -function queueHydrationError(error) { - if (hydrationErrors === null) { - hydrationErrors = [error]; - } else { - hydrationErrors.push(error); + try { + children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg + ); + } finally { + setIsStrictModeForDevtools(false); + } } -} -// we wait until the current render is over (either finished or interrupted) -// before adding it to the fiber/hook queue. Push to this array so we can -// access the queue, fiber, update, et al later. + finishRenderingHooks(current, workInProgress); + return children; +} -var concurrentQueues = []; -var concurrentQueuesIndex = 0; -var concurrentlyUpdatedLanes = NoLanes; -function finishQueueingConcurrentUpdates() { - var endIndex = concurrentQueuesIndex; - concurrentQueuesIndex = 0; - concurrentlyUpdatedLanes = NoLanes; - var i = 0; +function finishRenderingHooks(current, workInProgress) { + // 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-entrance. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; - while (i < endIndex) { - var fiber = concurrentQueues[i]; - concurrentQueues[i++] = null; - var queue = concurrentQueues[i]; - concurrentQueues[i++] = null; - var update = concurrentQueues[i]; - concurrentQueues[i++] = null; - var lane = concurrentQueues[i]; - concurrentQueues[i++] = null; + { + workInProgress._debugHookTypes = hookTypesDev; + } // This check uses currentHook so that it works the same in DEV and prod bundles. + // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. - if (queue !== null && update !== null) { - var pending = queue.pending; + var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; + renderLanes$1 = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + { + currentHookNameInDev = null; + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; // Confirm that a static flag was not added or removed since the last + // render. If this fires, it suggests that we incorrectly reset the static + // flags in some other part of the codebase. This has happened before, for + // example, in the SuspenseList implementation. - queue.pending = update; + if ( + current !== null && + (current.flags & StaticMask) !== (workInProgress.flags & StaticMask) && // Disable this warning in legacy mode, because legacy Suspense is weird + // and creates false positives. To make this work in legacy mode, we'd + // need to mark fibers that commit in an incomplete state, somehow. For + // now I'll disable the warning that most of the bugs that would trigger + // it are either exclusive to concurrent mode or exist in both. + (current.mode & ConcurrentMode) !== NoMode + ) { + error( + "Internal React error: Expected static flag was missing. Please " + + "notify the React team." + ); } + } - if (lane !== NoLane) { - markUpdateLaneFromFiberToRoot(fiber, update, lane); + didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook + // localIdCounter = 0; + + thenableIndexCounter = 0; + thenableState = null; + + if (didRenderTooFewHooks) { + throw new Error( + "Rendered fewer hooks than expected. This may be caused by an accidental " + + "early return statement." + ); + } + + if (enableLazyContextPropagation) { + if (current !== null) { + if (!checkIfWorkInProgressReceivedUpdate()) { + // If there were no changes to props or state, we need to check if there + // was a context change. We didn't already do this because there's no + // 1:1 correspondence between dependencies and hooks. Although, because + // there almost always is in the common case (`readContext` is an + // internal API), we could compare in there. OTOH, we only hit this case + // if everything else bails out, so on the whole it might be better to + // keep the comparison out of the common path. + var currentDependencies = current.dependencies; + + if ( + currentDependencies !== null && + checkIfContextChanged(currentDependencies) + ) { + markWorkInProgressReceivedUpdate(); + } + } } } -} -function getConcurrentlyUpdatedLanes() { - return concurrentlyUpdatedLanes; -} -function enqueueUpdate$1(fiber, queue, update, lane) { - // Don't update the `childLanes` on the return path yet. If we already in - // the middle of rendering, wait until after it has completed. - concurrentQueues[concurrentQueuesIndex++] = fiber; - concurrentQueues[concurrentQueuesIndex++] = queue; - concurrentQueues[concurrentQueuesIndex++] = update; - concurrentQueues[concurrentQueuesIndex++] = lane; - concurrentlyUpdatedLanes = mergeLanes(concurrentlyUpdatedLanes, lane); // The fiber's `lane` field is used in some places to check if any work is - // scheduled, to perform an eager bailout, so we need to update it immediately. - // TODO: We should probably move this to the "shared" queue instead. + { + if (checkIfUseWrappedInTryCatch()) { + var componentName = + getComponentNameFromFiber(workInProgress) || "Unknown"; - fiber.lanes = mergeLanes(fiber.lanes, lane); - var alternate = fiber.alternate; + if (!didWarnAboutUseWrappedInTryCatch.has(componentName)) { + didWarnAboutUseWrappedInTryCatch.add(componentName); - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); + error( + "`use` was called from inside a try/catch block. This is not allowed " + + "and can lead to unexpected behavior. To handle errors triggered " + + "by `use`, wrap your component in a error boundary." + ); + } + } } } -function enqueueConcurrentHookUpdate(fiber, queue, update, lane) { - var concurrentQueue = queue; - var concurrentUpdate = update; - enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); - return getRootForUpdatedFiber(fiber); -} -function enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update) { - // This function is used to queue an update that doesn't need a rerender. The - // only reason we queue it is in case there's a subsequent higher priority - // update that causes it to be rebased. - var lane = NoLane; - var concurrentQueue = queue; - var concurrentUpdate = update; - enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); // Usually we can rely on the upcoming render phase to process the concurrent - // queue. However, since this is a bail out, we're not scheduling any work - // here. So the update we just queued will leak until something else happens - // to schedule work (if ever). +function replaySuspendedComponentWithHooks( + current, + workInProgress, + Component, + props, + secondArg +) { + // This function is used to replay a component that previously suspended, + // after its data resolves. // - // Check if we're currently in the middle of rendering a tree, and if not, - // process the queue immediately to prevent a leak. - - var isConcurrentlyRendering = getWorkInProgressRoot() !== null; + // It's a simplified version of renderWithHooks, but it doesn't need to do + // most of the set up work because they weren't reset when we suspended; they + // only get reset when the component either completes (finishRenderingHooks) + // or unwinds (resetHooksOnUnwind). + { + hookTypesUpdateIndexDev = -1; // Used for hot reloading: - if (!isConcurrentlyRendering) { - finishQueueingConcurrentUpdates(); + ignorePreviousDependencies = + current !== null && current.type !== workInProgress.type; } -} -function enqueueConcurrentClassUpdate(fiber, queue, update, lane) { - var concurrentQueue = queue; - var concurrentUpdate = update; - enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); - return getRootForUpdatedFiber(fiber); -} -function enqueueConcurrentRenderForLane(fiber, lane) { - enqueueUpdate$1(fiber, null, null, lane); - return getRootForUpdatedFiber(fiber); -} // Calling this function outside this module should only be done for backwards -// compatibility and should always be accompanied by a warning. -function unsafe_markUpdateLaneFromFiberToRoot(sourceFiber, lane) { - // NOTE: For Hyrum's Law reasons, if an infinite update loop is detected, it - // should throw before `markUpdateLaneFromFiberToRoot` is called. But this is - // undefined behavior and we can change it if we need to; it just so happens - // that, at the time of this writing, there's an internal product test that - // happens to rely on this. - var root = getRootForUpdatedFiber(sourceFiber); - markUpdateLaneFromFiberToRoot(sourceFiber, null, lane); - return root; + var children = renderWithHooksAgain( + workInProgress, + Component, + props, + secondArg + ); + finishRenderingHooks(current, workInProgress); + return children; } -function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { - // Update the source fiber's lanes - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); - var alternate = sourceFiber.alternate; - - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, lane); - } // Walk the parent path to the root and update the child lanes. +function renderWithHooksAgain(workInProgress, Component, props, secondArg) { + // This is used to perform another render pass. It's used when setState is + // called during render, and for double invoking components in Strict Mode + // during development. + // + // The state from the previous pass is reused whenever possible. So, state + // updates that were already processed are not processed again, and memoized + // functions (`useMemo`) are not invoked again. + // + // Keep rendering in a loop for as long as render phase updates continue to + // be scheduled. Use a counter to prevent infinite loops. + var numberOfReRenders = 0; + var children; - var isHidden = false; - var parent = sourceFiber.return; - var node = sourceFiber; + do { + if (didScheduleRenderPhaseUpdateDuringThisPass) { + // It's possible that a use() value depended on a state that was updated in + // this rerender, so we need to watch for different thenables this time. + thenableState = null; + } - while (parent !== null) { - parent.childLanes = mergeLanes(parent.childLanes, lane); - alternate = parent.alternate; + thenableIndexCounter = 0; + didScheduleRenderPhaseUpdateDuringThisPass = false; - if (alternate !== null) { - alternate.childLanes = mergeLanes(alternate.childLanes, lane); + if (numberOfReRenders >= RE_RENDER_LIMIT) { + throw new Error( + "Too many re-renders. React limits the number of renders to prevent " + + "an infinite loop." + ); } - if (parent.tag === OffscreenComponent) { - // Check if this offscreen boundary is currently hidden. - // - // The instance may be null if the Offscreen parent was unmounted. Usually - // the parent wouldn't be reachable in that case because we disconnect - // fibers from the tree when they are deleted. However, there's a weird - // edge case where setState is called on a fiber that was interrupted - // before it ever mounted. Because it never mounts, it also never gets - // deleted. Because it never gets deleted, its return pointer never gets - // disconnected. Which means it may be attached to a deleted Offscreen - // parent node. (This discovery suggests it may be better for memory usage - // if we don't attach the `return` pointer until the commit phase, though - // in order to do that we'd need some other way to track the return - // pointer during the initial render, like on the stack.) - // - // This case is always accompanied by a warning, but we still need to - // account for it. (There may be other cases that we haven't discovered, - // too.) - var offscreenInstance = parent.stateNode; + numberOfReRenders += 1; - if ( - offscreenInstance !== null && - !(offscreenInstance._visibility & OffscreenVisible) - ) { - isHidden = true; - } + { + // Even when hot reloading, allow dependencies to stabilize + // after first render to prevent infinite render phase updates. + ignorePreviousDependencies = false; + } // Start over from the beginning of the list + + currentHook = null; + workInProgressHook = null; + workInProgress.updateQueue = null; + + { + // Also validate hook order for cascading updates. + hookTypesUpdateIndexDev = -1; } - node = parent; - parent = parent.return; - } + ReactCurrentDispatcher$1.current = HooksDispatcherOnRerenderInDEV; + children = Component(props, secondArg); + } while (didScheduleRenderPhaseUpdateDuringThisPass); - if (isHidden && update !== null && node.tag === HostRoot) { - var root = node.stateNode; - markHiddenUpdate(root, update, lane); - } + return children; } -function getRootForUpdatedFiber(sourceFiber) { - // TODO: We will detect and infinite update loop and throw even if this fiber - // has already unmounted. This isn't really necessary but it happens to be the - // current behavior we've used for several release cycles. Consider not - // performing this check if the updated fiber already unmounted, since it's - // not possible for that to cause an infinite update loop. - throwIfInfiniteUpdateLoopDetected(); // When a setState happens, we must ensure the root is scheduled. Because - // update queues do not have a backpointer to the root, the only way to do - // this currently is to walk up the return path. This used to not be a big - // deal because we would have to walk up the return path to set - // the `childLanes`, anyway, but now those two traversals happen at - // different times. - // TODO: Consider adding a `root` backpointer on the update queue. - - detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); - var node = sourceFiber; - var parent = node.return; +function checkDidRenderIdHook() { + // This should be called immediately after every renderWithHooks call. + // Conceptually, it's part of the return value of renderWithHooks; it's only a + // separate function to avoid using an array tuple. + var didRenderIdHook = localIdCounter !== 0; + localIdCounter = 0; + return didRenderIdHook; +} +function bailoutHooks(current, workInProgress, lanes) { + workInProgress.updateQueue = current.updateQueue; // TODO: Don't need to reset the flags here, because they're reset in the + // complete phase (bubbleProperties). - while (parent !== null) { - detectUpdateOnUnmountedFiber(sourceFiber, node); - node = parent; - parent = node.return; + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + workInProgress.flags &= ~( + MountPassiveDev | + MountLayoutDev | + Passive$1 | + Update + ); + } else { + workInProgress.flags &= ~(Passive$1 | Update); } - return node.tag === HostRoot ? node.stateNode : null; + current.lanes = removeLanes(current.lanes, lanes); +} +function resetHooksAfterThrow() { + // This is called immediaetly after a throw. It shouldn't reset the entire + // module state, because the work loop might decide to replay the component + // again without rewinding. + // + // It should only reset things like the current dispatcher, to prevent hooks + // from being called outside of a component. + // 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-entrance. + ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; } +function resetHooksOnUnwind() { + if (didScheduleRenderPhaseUpdate) { + // There were render phase updates. These are only valid for this render + // phase, which we are now aborting. Remove the updates from the queues so + // they do not persist to the next render. Do not remove updates from hooks + // that weren't processed. + // + // Only reset the updates from the queue if it has a clone. If it does + // not have a clone, that means it wasn't processed, and the updates were + // scheduled before we entered the render phase. + var hook = currentlyRenderingFiber$1.memoizedState; -function detectUpdateOnUnmountedFiber(sourceFiber, parent) { - { - var alternate = parent.alternate; + while (hook !== null) { + var queue = hook.queue; - if ( - alternate === null && - (parent.flags & (Placement | Hydrating)) !== NoFlags$1 - ) { - warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); + if (queue !== null) { + queue.pending = null; + } + + hook = hook.next; } + + didScheduleRenderPhaseUpdate = false; } -} -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`. + renderLanes$1 = NoLanes; + currentlyRenderingFiber$1 = null; + currentHook = null; + workInProgressHook = null; -var hasForceUpdate = false; -var didWarnUpdateInsideUpdate; -var currentlyProcessingQueue; + { + hookTypesDev = null; + hookTypesUpdateIndexDev = -1; + currentHookNameInDev = null; + } -{ - didWarnUpdateInsideUpdate = false; - currentlyProcessingQueue = null; + didScheduleRenderPhaseUpdateDuringThisPass = false; + localIdCounter = 0; + thenableIndexCounter = 0; + thenableState = null; } -function initializeUpdateQueue(fiber) { - var queue = { - baseState: fiber.memoizedState, - firstBaseUpdate: null, - lastBaseUpdate: null, - shared: { - pending: null, - lanes: NoLanes, - hiddenCallbacks: null - }, - callbacks: null - }; - fiber.updateQueue = queue; -} -function cloneUpdateQueue(current, workInProgress) { - // Clone the update queue from current. Unless it's already a clone. - var queue = workInProgress.updateQueue; - var currentQueue = current.updateQueue; - - if (queue === currentQueue) { - var clone = { - baseState: currentQueue.baseState, - firstBaseUpdate: currentQueue.firstBaseUpdate, - lastBaseUpdate: currentQueue.lastBaseUpdate, - shared: currentQueue.shared, - callbacks: null - }; - workInProgress.updateQueue = clone; - } -} -function createUpdate(lane) { - var update = { - lane: lane, - tag: UpdateState, - payload: null, - callback: null, +function mountWorkInProgressHook() { + var hook = { + memoizedState: null, + baseState: null, + baseQueue: null, + queue: null, next: null }; - return update; -} -function enqueueUpdate(fiber, update, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return null; + if (workInProgressHook === null) { + // This is the first hook in the list + currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook; + } else { + // Append to the end of the list + workInProgressHook = workInProgressHook.next = hook; } - var sharedQueue = updateQueue.shared; - - { - if ( - currentlyProcessingQueue === sharedQueue && - !didWarnUpdateInsideUpdate - ) { - var componentName = getComponentNameFromFiber(fiber); - - error( - "An update (setState, replaceState, or forceUpdate) was scheduled " + - "from inside an update function. Update functions should be pure, " + - "with zero side-effects. Consider using componentDidUpdate or a " + - "callback.\n\nPlease update the following component: %s", - componentName - ); + return workInProgressHook; +} - didWarnUpdateInsideUpdate = true; - } - } +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. + var nextCurrentHook; - if (isUnsafeClassRenderPhaseUpdate(fiber)) { - // This is an unsafe render phase update. Add directly to the update - // queue so we can process it immediately during the current render. - var pending = sharedQueue.pending; + if (currentHook === null) { + var current = currentlyRenderingFiber$1.alternate; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; + if (current !== null) { + nextCurrentHook = current.memoizedState; } else { - update.next = pending.next; - pending.next = update; + nextCurrentHook = null; } - - sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering - // this fiber. This is for backwards compatibility in the case where you - // update a different component during render phase than the one that is - // currently renderings (a pattern that is accompanied by a warning). - - return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); } else { - return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); + nextCurrentHook = currentHook.next; } -} -function entangleTransitions(root, fiber, lane) { - var updateQueue = fiber.updateQueue; - if (updateQueue === null) { - // Only occurs if the fiber has been unmounted. - return; - } + var nextWorkInProgressHook; - var sharedQueue = updateQueue.shared; + if (workInProgressHook === null) { + nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; + } else { + nextWorkInProgressHook = workInProgressHook.next; + } - if (isTransitionLane(lane)) { - var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must - // have finished. We can remove them from the shared queue, which represents - // a superset of the actually pending lanes. In some cases we may entangle - // more than we need to, but that's OK. In fact it's worse if we *don't* - // entangle when we should. + if (nextWorkInProgressHook !== null) { + // There's already a work-in-progress. Reuse it. + workInProgressHook = nextWorkInProgressHook; + nextWorkInProgressHook = workInProgressHook.next; + currentHook = nextCurrentHook; + } else { + // Clone from the current hook. + if (nextCurrentHook === null) { + var currentFiber = currentlyRenderingFiber$1.alternate; - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. + if (currentFiber === null) { + // This is the initial render. This branch is reached when the component + // suspends, resumes, then renders an additional hook. + // Should never be reached because we should switch to the mount dispatcher first. + throw new Error( + "Update hook called on initial render. This is likely a bug in React. Please file an issue." + ); + } else { + // This is an update. We should always have a current hook. + throw new Error("Rendered more hooks than during the previous render."); + } + } - var newQueueLanes = mergeLanes(queueLanes, lane); - sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if - // the lane finished since the last time we entangled it. So we need to - // entangle it again, just to be sure. + currentHook = nextCurrentHook; + var newHook = { + memoizedState: currentHook.memoizedState, + baseState: currentHook.baseState, + baseQueue: currentHook.baseQueue, + queue: currentHook.queue, + next: null + }; - markRootEntangled(root, newQueueLanes); + if (workInProgressHook === null) { + // This is the first hook in the list. + currentlyRenderingFiber$1.memoizedState = workInProgressHook = newHook; + } else { + // Append to the end of the list. + workInProgressHook = workInProgressHook.next = newHook; + } } -} -function enqueueCapturedUpdate(workInProgress, capturedUpdate) { - // Captured updates are updates that are thrown by a child during the render - // phase. They should be discarded if the render is aborted. Therefore, - // we should only put them on the work-in-progress queue, not the current one. - var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. - var current = workInProgress.alternate; + return workInProgressHook; +} // NOTE: defining two versions of this function to avoid size impact when this feature is disabled. +// Previously this function was inlined, the additional `memoCache` property makes it not inlined. - if (current !== null) { - var currentQueue = current.updateQueue; +var createFunctionComponentUpdateQueue; - if (queue === currentQueue) { - // The work-in-progress queue is the same as current. This happens when - // we bail out on a parent fiber that then captures an error thrown by - // a child. Since we want to append the update only to the work-in - // -progress queue, we need to clone the updates. We usually clone during - // processUpdateQueue, but that didn't happen in this case because we - // skipped over the parent when we bailed out. - var newFirst = null; - var newLast = null; - var firstBaseUpdate = queue.firstBaseUpdate; +{ + createFunctionComponentUpdateQueue = function () { + return { + lastEffect: null, + events: null, + stores: null, + memoCache: null + }; + }; +} - if (firstBaseUpdate !== null) { - // Loop through the updates and clone them. - var update = firstBaseUpdate; +function use(usable) { + if (usable !== null && typeof usable === "object") { + // $FlowFixMe[method-unbinding] + if (typeof usable.then === "function") { + // This is a thenable. + var thenable = usable; // Track the position of the thenable within this fiber. - do { - var clone = { - lane: update.lane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, - next: null - }; + var index = thenableIndexCounter; + thenableIndexCounter += 1; - if (newLast === null) { - newFirst = newLast = clone; - } else { - newLast.next = clone; - newLast = clone; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + if (thenableState === null) { + thenableState = createThenableState(); + } - update = update.next; - } while (update !== null); // Append the captured update the end of the cloned list. + var result = trackUsedThenable(thenableState, thenable, index); - if (newLast === null) { - newFirst = newLast = capturedUpdate; - } else { - newLast.next = capturedUpdate; - newLast = capturedUpdate; + if ( + currentlyRenderingFiber$1.alternate === null && + (workInProgressHook === null + ? currentlyRenderingFiber$1.memoizedState === null + : workInProgressHook.next === null) + ) { + // Initial render, and either this is the first time the component is + // called, or there were no Hooks called after this use() the previous + // time (perhaps because it threw). Subsequent Hook calls should use the + // mount dispatcher. + { + ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; } - } else { - // There are no base updates. - newFirst = newLast = capturedUpdate; } - queue = { - baseState: currentQueue.baseState, - firstBaseUpdate: newFirst, - lastBaseUpdate: newLast, - shared: currentQueue.shared, - callbacks: currentQueue.callbacks - }; - workInProgress.updateQueue = queue; - return; + return result; + } else if ( + usable.$$typeof === REACT_CONTEXT_TYPE || + usable.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = usable; + return readContext(context); } - } // Append the update to the end of the list. - - var lastBaseUpdate = queue.lastBaseUpdate; - - if (lastBaseUpdate === null) { - queue.firstBaseUpdate = capturedUpdate; - } else { - lastBaseUpdate.next = capturedUpdate; - } + } // eslint-disable-next-line react-internal/safe-string-coercion - queue.lastBaseUpdate = capturedUpdate; + throw new Error("An unsupported type was passed to use(): " + String(usable)); } -function getStateFromUpdate( - workInProgress, - queue, - update, - prevState, - nextProps, - instance -) { - switch (update.tag) { - case ReplaceState: { - var payload = update.payload; - - if (typeof payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); - } - - var nextState = payload.call(instance, prevState, nextProps); - - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); - - try { - payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } +function useMemoCache(size) { + var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared - exitDisallowedContextReadInDEV(); - } + var updateQueue = currentlyRenderingFiber$1.updateQueue; - return nextState; - } // State object + if (updateQueue !== null) { + memoCache = updateQueue.memoCache; + } // Otherwise clone from the current fiber - return payload; - } + if (memoCache == null) { + var current = currentlyRenderingFiber$1.alternate; - case CaptureUpdate: { - workInProgress.flags = - (workInProgress.flags & ~ShouldCapture) | DidCapture; - } - // Intentional fallthrough + if (current !== null) { + var currentUpdateQueue = current.updateQueue; - case UpdateState: { - var _payload = update.payload; - var partialState; + if (currentUpdateQueue !== null) { + var currentMemoCache = currentUpdateQueue.memoCache; - if (typeof _payload === "function") { - // Updater function - { - enterDisallowedContextReadInDEV(); + if (currentMemoCache != null) { + memoCache = { + data: currentMemoCache.data.map(function (array) { + return array.slice(); + }), + index: 0 + }; } + } + } + } // Finally fall back to allocating a fresh instance of the cache - partialState = _payload.call(instance, prevState, nextProps); - - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + if (memoCache == null) { + memoCache = { + data: [], + index: 0 + }; + } - try { - _payload.call(instance, prevState, nextProps); - } finally { - setIsStrictModeForDevtools(false); - } - } + if (updateQueue === null) { + updateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = updateQueue; + } - exitDisallowedContextReadInDEV(); - } - } else { - // Partial state object - partialState = _payload; - } + updateQueue.memoCache = memoCache; + var data = memoCache.data[memoCache.index]; - if (partialState === null || partialState === undefined) { - // Null and undefined are treated as no-ops. - return prevState; - } // Merge the partial state and the previous state. + if (data === undefined) { + data = memoCache.data[memoCache.index] = new Array(size); - return assign({}, prevState, partialState); + for (var i = 0; i < size; i++) { + data[i] = REACT_MEMO_CACHE_SENTINEL; } - - case ForceUpdate: { - hasForceUpdate = true; - return prevState; + } else if (data.length !== size) { + // TODO: consider warning or throwing here + { + error( + "Expected a constant size argument for each invocation of useMemoCache. " + + "The previous cache was allocated with size %s but size %s was requested.", + data.length, + size + ); } } - return prevState; + memoCache.index++; + return data; } -function processUpdateQueue(workInProgress, props, instance, renderLanes) { - // This is always non-null on a ClassComponent or HostRoot - var queue = workInProgress.updateQueue; - hasForceUpdate = false; - - { - currentlyProcessingQueue = queue.shared; - } +function basicStateReducer(state, action) { + // $FlowFixMe: Flow doesn't like mixed types + return typeof action === "function" ? action(state) : action; +} - var firstBaseUpdate = queue.firstBaseUpdate; - var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. +function mountReducer(reducer, initialArg, init) { + var hook = mountWorkInProgressHook(); + var initialState; - var pendingQueue = queue.shared.pending; + if (init !== undefined) { + initialState = init(initialArg); + } else { + initialState = initialArg; + } - if (pendingQueue !== null) { - queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first - // and last so that it's non-circular. + hook.memoizedState = hook.baseState = initialState; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: reducer, + lastRenderedState: initialState + }; + hook.queue = queue; + var dispatch = (queue.dispatch = dispatchReducerAction.bind( + null, + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; +} - var lastPendingUpdate = pendingQueue; - var firstPendingUpdate = lastPendingUpdate.next; - lastPendingUpdate.next = null; // Append pending updates to base queue +function updateReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; - if (lastBaseUpdate === null) { - firstBaseUpdate = firstPendingUpdate; - } else { - lastBaseUpdate.next = firstPendingUpdate; - } + if (queue === null) { + throw new Error( + "Should have a queue. This is likely a bug in React. Please file an issue." + ); + } - lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then - // we need to transfer the updates to that queue, too. Because the base - // queue is a singly-linked list with no cycles, we can append to both - // lists and take advantage of structural sharing. - // TODO: Pass `current` as argument + queue.lastRenderedReducer = reducer; + var current = currentHook; // The last rebase update that is NOT part of the base state. - var current = workInProgress.alternate; + var baseQueue = current.baseQueue; // The last pending update that hasn't been processed yet. - if (current !== null) { - // This is always non-null on a ClassComponent or HostRoot - var currentQueue = current.updateQueue; - var currentLastBaseUpdate = currentQueue.lastBaseUpdate; + var pendingQueue = queue.pending; - if (currentLastBaseUpdate !== lastBaseUpdate) { - if (currentLastBaseUpdate === null) { - currentQueue.firstBaseUpdate = firstPendingUpdate; - } else { - currentLastBaseUpdate.next = firstPendingUpdate; - } + if (pendingQueue !== null) { + // We have new updates that haven't been processed yet. + // We'll add them to the base queue. + if (baseQueue !== null) { + // Merge the pending queue and the base queue. + var baseFirst = baseQueue.next; + var pendingFirst = pendingQueue.next; + baseQueue.next = pendingFirst; + pendingQueue.next = baseFirst; + } - currentQueue.lastBaseUpdate = lastPendingUpdate; + { + if (current.baseQueue !== baseQueue) { + // Internal invariant that should never happen, but feasibly could in + // the future if we implement resuming, or some form of that. + error( + "Internal error: Expected work-in-progress queue to be a clone. " + + "This is a bug in React." + ); } } - } // These values may change as we process the queue. - if (firstBaseUpdate !== null) { - // Iterate through the list of updates to compute the result. - var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes - // from the original lanes. + current.baseQueue = baseQueue = pendingQueue; + queue.pending = null; + } - var newLanes = NoLanes; + if (baseQueue !== null) { + // We have a queue to process. + var first = baseQueue.next; + var newState = current.baseState; var newBaseState = null; - var newFirstBaseUpdate = null; - var newLastBaseUpdate = null; - var update = firstBaseUpdate; + var newBaseQueueFirst = null; + var newBaseQueueLast = null; + var update = first; do { // An extra OffscreenLane bit is added to updates that were made to @@ -18808,7 +17870,7 @@ function processUpdateQueue(workInProgress, props, instance, renderLanes) { var shouldSkipUpdate = isHiddenUpdate ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes, updateLane); + : !isSubsetOfLanes(renderLanes$1, updateLane); if (shouldSkipUpdate) { // Priority is insufficient. Skip this update. If this is the first @@ -18816,24473 +17878,25354 @@ function processUpdateQueue(workInProgress, props, instance, renderLanes) { // update/state. var clone = { lane: updateLane, - tag: update.tag, - payload: update.payload, - callback: update.callback, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, next: null }; - if (newLastBaseUpdate === null) { - newFirstBaseUpdate = newLastBaseUpdate = clone; + if (newBaseQueueLast === null) { + newBaseQueueFirst = newBaseQueueLast = clone; newBaseState = newState; } else { - newLastBaseUpdate = newLastBaseUpdate.next = clone; + newBaseQueueLast = newBaseQueueLast.next = clone; } // Update the remaining priority in the queue. + // TODO: Don't need to accumulate this. Instead, we can remove + // renderLanes from the original lanes. - newLanes = mergeLanes(newLanes, updateLane); + currentlyRenderingFiber$1.lanes = mergeLanes( + currentlyRenderingFiber$1.lanes, + updateLane + ); + markSkippedUpdateLanes(updateLane); } else { // This update does have sufficient priority. - if (newLastBaseUpdate !== null) { + if (newBaseQueueLast !== null) { var _clone = { // This update is going to be committed so we never want uncommit // it. Using NoLane works because 0 is a subset of all bitmasks, so // this will never be skipped by the check above. lane: NoLane, - tag: update.tag, - payload: update.payload, - // When this update is rebased, we should not fire its - // callback again. - callback: null, + action: update.action, + hasEagerState: update.hasEagerState, + eagerState: update.eagerState, next: null }; - newLastBaseUpdate = newLastBaseUpdate.next = _clone; + newBaseQueueLast = newBaseQueueLast.next = _clone; } // Process this update. - newState = getStateFromUpdate( - workInProgress, - queue, - update, - newState, - props, - instance - ); - var callback = update.callback; - - if (callback !== null) { - workInProgress.flags |= Callback; - - if (isHiddenUpdate) { - workInProgress.flags |= Visibility; - } - - var callbacks = queue.callbacks; + var action = update.action; - if (callbacks === null) { - queue.callbacks = [callback]; - } else { - callbacks.push(callback); - } + if (shouldDoubleInvokeUserFnsInHooksDEV) { + reducer(newState, action); } - } // $FlowFixMe[incompatible-type] we bail out when we get a null - - update = update.next; - - if (update === null) { - pendingQueue = queue.shared.pending; - if (pendingQueue === null) { - break; + if (update.hasEagerState) { + // If this update is a state update (not a reducer) and was processed eagerly, + // we can use the eagerly computed state + newState = update.eagerState; } else { - // An update was scheduled from inside a reducer. Add the new - // pending updates to the end of the list and keep processing. - var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we - // unravel them when transferring them to the base queue. - - var _firstPendingUpdate = _lastPendingUpdate.next; - _lastPendingUpdate.next = null; - update = _firstPendingUpdate; - queue.lastBaseUpdate = _lastPendingUpdate; - queue.shared.pending = null; + newState = reducer(newState, action); } } - } while (true); - if (newLastBaseUpdate === null) { - newBaseState = newState; - } + update = update.next; + } while (update !== null && update !== first); - queue.baseState = newBaseState; - queue.firstBaseUpdate = newFirstBaseUpdate; - queue.lastBaseUpdate = newLastBaseUpdate; + if (newBaseQueueLast === null) { + newBaseState = newState; + } else { + newBaseQueueLast.next = newBaseQueueFirst; + } // Mark that the fiber performed work, but only if the new state is + // different from the current state. - if (firstBaseUpdate === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.shared.lanes = NoLanes; - } // 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. + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); + } - markSkippedUpdateLanes(newLanes); - workInProgress.lanes = newLanes; - workInProgress.memoizedState = newState; + hook.memoizedState = newState; + hook.baseState = newBaseState; + hook.baseQueue = newBaseQueueLast; + queue.lastRenderedState = newState; } - { - currentlyProcessingQueue = null; + if (baseQueue === null) { + // `queue.lanes` is used for entangling transitions. We can set it back to + // zero once the queue is empty. + queue.lanes = NoLanes; } + + var dispatch = queue.dispatch; + return [hook.memoizedState, dispatch]; } -function callCallback(callback, context) { - if (typeof callback !== "function") { +function rerenderReducer(reducer, initialArg, init) { + var hook = updateWorkInProgressHook(); + var queue = hook.queue; + + if (queue === null) { throw new Error( - "Invalid argument passed as callback. Expected a function. Instead " + - ("received: " + callback) + "Should have a queue. This is likely a bug in React. Please file an issue." ); } - callback.call(context); -} - -function resetHasForceUpdateBeforeProcessing() { - hasForceUpdate = false; -} -function checkHasForceUpdateAfterProcessing() { - return hasForceUpdate; -} -function deferHiddenCallbacks(updateQueue) { - // When an update finishes on a hidden component, its callback should not - // be fired until/unless the component is made visible again. Stash the - // callback on the shared queue object so it can be fired later. - var newHiddenCallbacks = updateQueue.callbacks; + queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous + // work-in-progress hook. - if (newHiddenCallbacks !== null) { - var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; + var dispatch = queue.dispatch; + var lastRenderPhaseUpdate = queue.pending; + var newState = hook.memoizedState; - if (existingHiddenCallbacks === null) { - updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; - } else { - updateQueue.shared.hiddenCallbacks = - existingHiddenCallbacks.concat(newHiddenCallbacks); - } - } -} -function commitHiddenCallbacks(updateQueue, context) { - // This component is switching from hidden -> visible. Commit any callbacks - // that were previously deferred. - var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; + if (lastRenderPhaseUpdate !== null) { + // The queue doesn't persist past this render pass. + queue.pending = null; + var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; + var update = firstRenderPhaseUpdate; - if (hiddenCallbacks !== null) { - updateQueue.shared.hiddenCallbacks = null; + 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 !== firstRenderPhaseUpdate); // Mark that the fiber performed work, but only if the new state is + // different from the current state. - for (var i = 0; i < hiddenCallbacks.length; i++) { - var callback = hiddenCallbacks[i]; - callCallback(callback, context); + if (!objectIs(newState, hook.memoizedState)) { + markWorkInProgressReceivedUpdate(); } - } -} -function commitCallbacks(updateQueue, context) { - var callbacks = updateQueue.callbacks; - if (callbacks !== null) { - updateQueue.callbacks = null; + hook.memoizedState = newState; // Don't persist the state accumulated 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. - for (var i = 0; i < callbacks.length; i++) { - var callback = callbacks[i]; - callCallback(callback, context); + if (hook.baseQueue === null) { + hook.baseState = newState; } - } -} - -var ReactStrictModeWarnings = { - recordUnsafeLifecycleWarnings: function (fiber, instance) {}, - flushPendingUnsafeLifecycleWarnings: function () {}, - recordLegacyContextWarning: function (fiber, instance) {}, - flushLegacyContextWarning: function () {}, - discardPendingWarnings: function () {} -}; -{ - var findStrictRoot = function (fiber) { - var maybeStrictRoot = null; - var node = fiber; + queue.lastRenderedState = newState; + } - while (node !== null) { - if (node.mode & StrictLegacyMode) { - maybeStrictRoot = node; - } + return [newState, dispatch]; +} - node = node.return; - } +function readFromUnsubscribedMutableSource(root, source, getSnapshot) { + { + warnAboutMultipleRenderersDEV(source); + } - return maybeStrictRoot; - }; + var getVersion = source._getVersion; + var version = getVersion(source._source); // Is it safe for this component to read from this source during the current render? - var setToSortedString = function (set) { - var array = []; - set.forEach(function (value) { - array.push(value); - }); - return array.sort().join(", "); - }; + var isSafeToReadFromSource = false; // Check the version first. + // If this render has already been started with a specific version, + // we can use it alone to determine if we can safely read from the source. - var pendingComponentWillMountWarnings = []; - var pendingUNSAFE_ComponentWillMountWarnings = []; - var pendingComponentWillReceivePropsWarnings = []; - var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - var pendingComponentWillUpdateWarnings = []; - var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. + var currentRenderVersion = getWorkInProgressVersion(source); - var didWarnAboutUnsafeLifecycles = new Set(); + if (currentRenderVersion !== null) { + // It's safe to read if the store hasn't been mutated since the last time + // we read something. + isSafeToReadFromSource = currentRenderVersion === version; + } else { + // If there's no version, then this is the first time we've read from the + // source during the current render pass, so we need to do a bit more work. + // What we need to determine is if there are any hooks that already + // subscribed to the source, and if so, whether there are any pending + // mutations that haven't been synchronized yet. + // + // If there are no pending mutations, then `root.mutableReadLanes` will be + // empty, and we know we can safely read. + // + // If there *are* pending mutations, we may still be able to safely read + // if the currently rendering lanes are inclusive of the pending mutation + // lanes, since that guarantees that the value we're about to read from + // the source is consistent with the values that we read during the most + // recent mutation. + isSafeToReadFromSource = isSubsetOfLanes( + renderLanes$1, + root.mutableReadLanes + ); - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( - fiber, - instance - ) { - // Dedupe strategy: Warn once per component. - if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { - return; + if (isSafeToReadFromSource) { + // If it's safe to read from this source during the current render, + // store the version in case other components read from it. + // A changed version number will let those components know to throw and restart the render. + setWorkInProgressVersion(source, version); } + } - if ( - typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - pendingComponentWillMountWarnings.push(fiber); - } + if (isSafeToReadFromSource) { + var snapshot = getSnapshot(source._source); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillMount === "function" - ) { - pendingUNSAFE_ComponentWillMountWarnings.push(fiber); + { + if (typeof snapshot === "function") { + error( + "Mutable source should not return a function as the snapshot value. " + + "Functions may close over mutable values and cause tearing." + ); + } } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== true - ) { - pendingComponentWillReceivePropsWarnings.push(fiber); - } + return snapshot; + } else { + // This handles the special case of a mutable source being shared between renderers. + // In that case, if the source is mutated between the first and second renderer, + // The second renderer don't know that it needs to reset the WIP version during unwind, + // (because the hook only marks sources as dirty if it's written to their WIP version). + // That would cause this tear check to throw again and eventually be visible to the user. + // We can avoid this infinite loop by explicitly marking the source as dirty. + // + // This can lead to tearing in the first renderer when it resumes, + // but there's nothing we can do about that (short of throwing here and refusing to continue the render). + markSourceAsDirty(source); // Intentioally throw an error to force React to retry synchronously. During + // the synchronous retry, it will block interleaved mutations, so we should + // get a consistent read. Therefore, the following error should never be + // visible to the user. + // We expect this error not to be thrown during the synchronous retry, + // because we blocked interleaved mutations. - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); - } + throw new Error( + "Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue." + ); + } +} - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - pendingComponentWillUpdateWarnings.push(fiber); - } +function useMutableSource(hook, source, getSnapshot, subscribe) { + var root = getWorkInProgressRoot(); - if ( - fiber.mode & StrictLegacyMode && - typeof instance.UNSAFE_componentWillUpdate === "function" - ) { - pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); - } - }; + if (root === null) { + throw new Error( + "Expected a work-in-progress root. This is a bug in React. Please file an issue." + ); + } - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { - // We do an initial pass to gather component names - var componentWillMountUniqueNames = new Set(); + var getVersion = source._getVersion; + var version = getVersion(source._source); + var dispatcher = ReactCurrentDispatcher$1.current; // eslint-disable-next-line prefer-const - if (pendingComponentWillMountWarnings.length > 0) { - pendingComponentWillMountWarnings.forEach(function (fiber) { - componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillMountWarnings = []; - } + var _dispatcher$useState = dispatcher.useState(function () { + return readFromUnsubscribedMutableSource(root, source, getSnapshot); + }), + currentSnapshot = _dispatcher$useState[0], + setSnapshot = _dispatcher$useState[1]; - var UNSAFE_componentWillMountUniqueNames = new Set(); + var snapshot = currentSnapshot; // Grab a handle to the state hook as well. + // We use it to clear the pending update queue if we have a new source. - if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { - pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { - UNSAFE_componentWillMountUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillMountWarnings = []; - } + var stateHook = workInProgressHook; + var memoizedState = hook.memoizedState; + var refs = memoizedState.refs; + var prevGetSnapshot = refs.getSnapshot; + var prevSource = memoizedState.source; + var prevSubscribe = memoizedState.subscribe; + var fiber = currentlyRenderingFiber$1; + hook.memoizedState = { + refs: refs, + source: source, + subscribe: subscribe + }; // Sync the values needed by our subscription handler after each commit. - var componentWillReceivePropsUniqueNames = new Set(); + dispatcher.useEffect( + function () { + refs.getSnapshot = getSnapshot; // Normally the dispatch function for a state hook never changes, + // but this hook recreates the queue in certain cases to avoid updates from stale sources. + // handleChange() below needs to reference the dispatch function without re-subscribing, + // so we use a ref to ensure that it always has the latest version. - if (pendingComponentWillReceivePropsWarnings.length > 0) { - pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { - componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillReceivePropsWarnings = []; - } + refs.setSnapshot = setSnapshot; // Check for a possible change between when we last rendered now. - var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); + var maybeNewVersion = getVersion(source._source); - if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { - pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { - UNSAFE_componentWillReceivePropsUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - } + if (!objectIs(version, maybeNewVersion)) { + var maybeNewSnapshot = getSnapshot(source._source); - var componentWillUpdateUniqueNames = new Set(); + { + if (typeof maybeNewSnapshot === "function") { + error( + "Mutable source should not return a function as the snapshot value. " + + "Functions may close over mutable values and cause tearing." + ); + } + } - if (pendingComponentWillUpdateWarnings.length > 0) { - pendingComponentWillUpdateWarnings.forEach(function (fiber) { - componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingComponentWillUpdateWarnings = []; - } + if (!objectIs(snapshot, maybeNewSnapshot)) { + setSnapshot(maybeNewSnapshot); + var lane = requestUpdateLane(fiber); + markRootMutableRead(root, lane); + } // If the source mutated between render and now, + // there may be state updates already scheduled from the old source. + // Entangle the updates so that they render in the same batch. - var UNSAFE_componentWillUpdateUniqueNames = new Set(); + markRootEntangled(root, root.mutableReadLanes); + } + }, + [getSnapshot, source, subscribe] + ); // If we got a new source or subscribe function, re-subscribe in a passive effect. - if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { - pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { - UNSAFE_componentWillUpdateUniqueNames.add( - getComponentNameFromFiber(fiber) || "Component" - ); - didWarnAboutUnsafeLifecycles.add(fiber.type); - }); - pendingUNSAFE_ComponentWillUpdateWarnings = []; - } // Finally, we flush all the warnings - // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' + dispatcher.useEffect( + function () { + var handleChange = function () { + var latestGetSnapshot = refs.getSnapshot; + var latestSetSnapshot = refs.setSnapshot; - if (UNSAFE_componentWillMountUniqueNames.size > 0) { - var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); + try { + latestSetSnapshot(latestGetSnapshot(source._source)); // Record a pending mutable source update with the same expiration time. - error( - "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "\nPlease update the following components: %s", - sortedNames - ); - } + var lane = requestUpdateLane(fiber); + markRootMutableRead(root, lane); + } catch (error) { + // A selector might throw after a source mutation. + // e.g. it might try to read from a part of the store that no longer exists. + // In this case we should still schedule an update with React. + // Worst case the selector will throw again and then an error boundary will handle it. + latestSetSnapshot(function () { + throw error; + }); + } + }; - if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames = setToSortedString( - UNSAFE_componentWillReceivePropsUniqueNames - ); + var unsubscribe = subscribe(source._source, handleChange); - error( - "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, " + - "refactor your code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "\nPlease update the following components: %s", - _sortedNames - ); - } + { + if (typeof unsubscribe !== "function") { + error( + "Mutable source subscribe function must return an unsubscribe function." + ); + } + } - if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { - var _sortedNames2 = setToSortedString( - UNSAFE_componentWillUpdateUniqueNames - ); + return unsubscribe; + }, + [source, subscribe] + ); // If any of the inputs to useMutableSource change, reading is potentially unsafe. + // + // If either the source or the subscription have changed we can't can't trust the update queue. + // Maybe the source changed in a way that the old subscription ignored but the new one depends on. + // + // If the getSnapshot function changed, we also shouldn't rely on the update queue. + // It's possible that the underlying source was mutated between the when the last "change" event fired, + // and when the current render (with the new getSnapshot function) is processed. + // + // In both cases, we need to throw away pending updates (since they are no longer relevant) + // and treat reading from the source as we do in the mount case. - error( - "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + - "and may indicate bugs in your code. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "\nPlease update the following components: %s", - _sortedNames2 - ); - } + if ( + !objectIs(prevGetSnapshot, getSnapshot) || + !objectIs(prevSource, source) || + !objectIs(prevSubscribe, subscribe) + ) { + // Create a new queue and setState method, + // So if there are interleaved updates, they get pushed to the older queue. + // When this becomes current, the previous queue and dispatch method will be discarded, + // including any interleaving updates that occur. + var newQueue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: snapshot + }; + newQueue.dispatch = setSnapshot = dispatchSetState.bind( + null, + currentlyRenderingFiber$1, + newQueue + ); + stateHook.queue = newQueue; + stateHook.baseQueue = null; + snapshot = readFromUnsubscribedMutableSource(root, source, getSnapshot); + stateHook.memoizedState = stateHook.baseState = snapshot; + } - if (componentWillMountUniqueNames.size > 0) { - var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); + return snapshot; +} - warn( - "componentWillMount has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + - "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames3 - ); - } +function mountMutableSource(source, getSnapshot, subscribe) { + var hook = mountWorkInProgressHook(); + hook.memoizedState = { + refs: { + getSnapshot: getSnapshot, + setSnapshot: null + }, + source: source, + subscribe: subscribe + }; + return useMutableSource(hook, source, getSnapshot, subscribe); +} - if (componentWillReceivePropsUniqueNames.size > 0) { - var _sortedNames4 = setToSortedString( - componentWillReceivePropsUniqueNames - ); +function updateMutableSource(source, getSnapshot, subscribe) { + var hook = updateWorkInProgressHook(); + return useMutableSource(hook, source, getSnapshot, subscribe); +} - warn( - "componentWillReceiveProps has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* If you're updating state whenever props change, refactor your " + - "code to use memoization techniques or move it to " + - "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + - "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames4 +function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var fiber = currentlyRenderingFiber$1; + var hook = mountWorkInProgressHook(); + var nextSnapshot; + var isHydrating = getIsHydrating(); + + if (isHydrating) { + if (getServerSnapshot === undefined) { + throw new Error( + "Missing getServerSnapshot, which is required for " + + "server-rendered content. Will revert to client rendering." ); } - if (componentWillUpdateUniqueNames.size > 0) { - var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); + nextSnapshot = getServerSnapshot(); - warn( - "componentWillUpdate has been renamed, and is not recommended for use. " + - "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + - "* Move data fetching code or side effects to componentDidUpdate.\n" + - "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + - "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + - "To rename all deprecated lifecycles to their new names, you can run " + - "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + - "\nPlease update the following components: %s", - _sortedNames5 - ); + { + if (!didWarnUncachedGetSnapshot) { + if (nextSnapshot !== getServerSnapshot()) { + error( + "The result of getServerSnapshot should be cached to avoid an infinite loop" + ); + + didWarnUncachedGetSnapshot = true; + } + } } - }; + } else { + nextSnapshot = getSnapshot(); - var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. + { + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); - var didWarnAboutLegacyContext = new Set(); + if (!objectIs(nextSnapshot, cachedSnapshot)) { + error( + "The result of getSnapshot should be cached to avoid an infinite loop" + ); - ReactStrictModeWarnings.recordLegacyContextWarning = function ( - fiber, - instance - ) { - var strictRoot = findStrictRoot(fiber); + didWarnUncachedGetSnapshot = true; + } + } + } // Unless we're rendering a blocking lane, schedule a consistency check. + // Right before committing, we will walk the tree and check if any of the + // stores were mutated. + // + // We won't do this if we're hydrating server-rendered content, because if + // the content is stale, it's already visible anyway. Instead we'll patch + // it up in a passive effect. - if (strictRoot === null) { - error( - "Expected to find a StrictMode component in a strict mode tree. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + var root = getWorkInProgressRoot(); - return; - } // Dedup strategy: Warn once per component. + if (root === null) { + throw new Error( + "Expected a work-in-progress root. This is a bug in React. Please file an issue." + ); + } - if (didWarnAboutLegacyContext.has(fiber.type)) { - return; + if (!includesBlockingLane(root, renderLanes$1)) { + pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); } + } // Read the current snapshot from the store on every render. This breaks the + // normal rules of React, and only works because store updates are + // always synchronous. - var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); + hook.memoizedState = nextSnapshot; + var inst = { + value: nextSnapshot, + getSnapshot: getSnapshot + }; + hook.queue = inst; // Schedule an effect to subscribe to the store. - if ( - fiber.type.contextTypes != null || - fiber.type.childContextTypes != null || - (instance !== null && typeof instance.getChildContext === "function") - ) { - if (warningsForRoot === undefined) { - warningsForRoot = []; - pendingLegacyContextWarning.set(strictRoot, warningsForRoot); - } + mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [subscribe]); // Schedule an effect to update the mutable instance fields. We will update + // this whenever subscribe, getSnapshot, or value changes. Because there's no + // clean-up function, and we track the deps correctly, we can call pushEffect + // directly, without storing any additional state. For the same reason, we + // don't need to set a static flag, either. + // TODO: We can move this to the passive phase once we add a pre-commit + // consistency check. See the next comment. - warningsForRoot.push(fiber); - } - }; + fiber.flags |= Passive$1; + pushEffect( + HasEffect | Passive, + updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), + undefined, + null + ); + return nextSnapshot; +} - ReactStrictModeWarnings.flushLegacyContextWarning = function () { - pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { - if (fiberArray.length === 0) { - return; - } +function updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { + var fiber = currentlyRenderingFiber$1; + var hook = updateWorkInProgressHook(); // Read the current snapshot from the store on every render. This breaks the + // normal rules of React, and only works because store updates are + // always synchronous. - var firstFiber = fiberArray[0]; - var uniqueNames = new Set(); - fiberArray.forEach(function (fiber) { - uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); - didWarnAboutLegacyContext.add(fiber.type); - }); - var sortedNames = setToSortedString(uniqueNames); + var nextSnapshot = getSnapshot(); - try { - setCurrentFiber(firstFiber); + { + if (!didWarnUncachedGetSnapshot) { + var cachedSnapshot = getSnapshot(); + if (!objectIs(nextSnapshot, cachedSnapshot)) { error( - "Legacy context API has been detected within a strict-mode tree." + - "\n\nThe old API will be supported in all 16.x releases, but applications " + - "using it should migrate to the new version." + - "\n\nPlease update the following components: %s" + - "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", - sortedNames + "The result of getSnapshot should be cached to avoid an infinite loop" ); - } finally { - resetCurrentFiber(); - } - }); - }; - - ReactStrictModeWarnings.discardPendingWarnings = function () { - pendingComponentWillMountWarnings = []; - pendingUNSAFE_ComponentWillMountWarnings = []; - pendingComponentWillReceivePropsWarnings = []; - pendingUNSAFE_ComponentWillReceivePropsWarnings = []; - pendingComponentWillUpdateWarnings = []; - pendingUNSAFE_ComponentWillUpdateWarnings = []; - pendingLegacyContextWarning = new Map(); - }; -} - -var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we -// detect this is caught by userspace, we'll log a warning in development. -var SuspenseException = new Error( - "Suspense Exception: This is not a real error! It's an implementation " + - "detail of `use` to interrupt the current render. You must either " + - "rethrow it immediately, or move the `use` call outside of the " + - "`try/catch` block. Capturing without rethrowing will lead to " + - "unexpected behavior.\n\n" + - "To handle async errors, wrap your component in an error boundary, or " + - "call the promise's `.catch` method and pass the result to `use`" -); -function createThenableState() { - // The ThenableState is created the first time a component suspends. If it - // suspends again, we'll reuse the same state. - return []; -} -function isThenableResolved(thenable) { - var status = thenable.status; - return status === "fulfilled" || status === "rejected"; -} + didWarnUncachedGetSnapshot = true; + } + } + } -function noop() {} + var prevSnapshot = (currentHook || hook).memoizedState; + var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); -function trackUsedThenable(thenableState, thenable, index) { - if (ReactCurrentActQueue$2.current !== null) { - ReactCurrentActQueue$2.didUsePromise = true; + if (snapshotChanged) { + hook.memoizedState = nextSnapshot; + markWorkInProgressReceivedUpdate(); } - var previous = thenableState[index]; + var inst = hook.queue; + updateEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [ + subscribe + ]); // Whenever getSnapshot or subscribe changes, we need to check in the + // commit phase if there was an interleaved mutation. In concurrent mode + // this can happen all the time, but even in synchronous mode, an earlier + // effect may have mutated the store. - if (previous === undefined) { - thenableState.push(thenable); - } else { - if (previous !== thenable) { - // Reuse the previous thenable, and drop the new one. We can assume - // they represent the same value, because components are idempotent. - // Avoid an unhandled rejection errors for the Promises that we'll - // intentionally ignore. - thenable.then(noop, noop); - thenable = previous; - } - } // We use an expando to track the status and result of a thenable so that we - // can synchronously unwrap the value. Think of this as an extension of the - // Promise API, or a custom interface that is a superset of Thenable. - // - // If the thenable doesn't have a status, set it to "pending" and attach - // a listener that will update its status and result when it resolves. + if ( + inst.getSnapshot !== getSnapshot || + snapshotChanged || // Check if the susbcribe function changed. We can save some memory by + // checking whether we scheduled a subscription effect above. + (workInProgressHook !== null && + workInProgressHook.memoizedState.tag & HasEffect) + ) { + fiber.flags |= Passive$1; + pushEffect( + HasEffect | Passive, + updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), + undefined, + null + ); // Unless we're rendering a blocking lane, schedule a consistency check. + // Right before committing, we will walk the tree and check if any of the + // stores were mutated. - switch (thenable.status) { - case "fulfilled": { - var fulfilledValue = thenable.value; - return fulfilledValue; - } + var root = getWorkInProgressRoot(); - case "rejected": { - var rejectedError = thenable.reason; - throw rejectedError; + if (root === null) { + throw new Error( + "Expected a work-in-progress root. This is a bug in React. Please file an issue." + ); } - default: { - if (typeof thenable.status === "string") { - // Only instrument the thenable if the status if not defined. If - // it's defined, but an unknown value, assume it's been instrumented by - // some custom userspace implementation. We treat it as "pending". - // Attach a dummy listener, to ensure that any lazy initialization can - // happen. Flight lazily parses JSON when the value is actually awaited. - thenable.then(noop, noop); - } else { - var pendingThenable = thenable; - pendingThenable.status = "pending"; - pendingThenable.then( - function (fulfilledValue) { - if (thenable.status === "pending") { - var fulfilledThenable = thenable; - fulfilledThenable.status = "fulfilled"; - fulfilledThenable.value = fulfilledValue; - } - }, - function (error) { - if (thenable.status === "pending") { - var rejectedThenable = thenable; - rejectedThenable.status = "rejected"; - rejectedThenable.reason = error; - } - } - ); - } // Check one more time in case the thenable resolved synchronously. - - switch (thenable.status) { - case "fulfilled": { - var fulfilledThenable = thenable; - return fulfilledThenable.value; - } + if (!includesBlockingLane(root, renderLanes$1)) { + pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + } + } - case "rejected": { - var rejectedThenable = thenable; - throw rejectedThenable.reason; - } - } // Suspend. - // - // Throwing here is an implementation detail that allows us to unwind the - // call stack. But we shouldn't allow it to leak into userspace. Throw an - // opaque placeholder value instead of the actual thenable. If it doesn't - // get captured by the work loop, log a warning, because that means - // something in userspace must have caught it. + return nextSnapshot; +} - suspendedThenable = thenable; +function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { + fiber.flags |= StoreConsistency; + var check = { + getSnapshot: getSnapshot, + value: renderedSnapshot + }; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; - { - needsToResetSuspendedThenableDEV = true; - } + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.stores = [check]; + } else { + var stores = componentUpdateQueue.stores; - throw SuspenseException; + if (stores === null) { + componentUpdateQueue.stores = [check]; + } else { + stores.push(check); } } -} // This is used to track the actual thenable that suspended so it can be -// passed to the rest of the Suspense implementation — which, for historical -// reasons, expects to receive a thenable. - -var suspendedThenable = null; -var needsToResetSuspendedThenableDEV = false; -function getSuspendedThenable() { - // This is called right after `use` suspends by throwing an exception. `use` - // throws an opaque value instead of the thenable itself so that it can't be - // caught in userspace. Then the work loop accesses the actual thenable using - // this function. - if (suspendedThenable === null) { - throw new Error( - "Expected a suspended thenable. This is a bug in React. Please file " + - "an issue." - ); - } +} - var thenable = suspendedThenable; - suspendedThenable = null; +function updateStoreInstance(fiber, inst, nextSnapshot, getSnapshot) { + // These are updated in the passive phase + inst.value = nextSnapshot; + inst.getSnapshot = getSnapshot; // Something may have been mutated in between render and commit. This could + // have been in an event that fired before the passive effects, or it could + // have been in a layout effect. In that case, we would have used the old + // snapsho and getSnapshot values to bail out. We need to check one more time. - { - needsToResetSuspendedThenableDEV = false; + if (checkIfSnapshotChanged(inst)) { + // Force a re-render. + forceStoreRerender(fiber); } - - return thenable; } -function checkIfUseWrappedInTryCatch() { - { - // This was set right before SuspenseException was thrown, and it should - // have been cleared when the exception was handled. If it wasn't, - // it must have been caught by userspace. - if (needsToResetSuspendedThenableDEV) { - needsToResetSuspendedThenableDEV = false; - return true; + +function subscribeToStore(fiber, inst, subscribe) { + var handleStoreChange = function () { + // The store changed. Check if the snapshot changed since the last time we + // read from the store. + if (checkIfSnapshotChanged(inst)) { + // Force a re-render. + forceStoreRerender(fiber); } - } + }; // Subscribe to the store and return a clean-up function. - return false; + return subscribe(handleStoreChange); } -var thenableState$1 = null; -var thenableIndexCounter$1 = 0; -var didWarnAboutMaps; -var didWarnAboutGenerators; -var didWarnAboutStringRefs; -var ownerHasKeyUseWarning; -var ownerHasFunctionTypeWarning; - -var warnForMissingKey = function (child, returnFiber) {}; +function checkIfSnapshotChanged(inst) { + var latestGetSnapshot = inst.getSnapshot; + var prevValue = inst.value; -{ - didWarnAboutMaps = false; - didWarnAboutGenerators = false; - didWarnAboutStringRefs = {}; - /** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ - - ownerHasKeyUseWarning = {}; - ownerHasFunctionTypeWarning = {}; - - warnForMissingKey = function (child, returnFiber) { - if (child === null || typeof child !== "object") { - return; - } - - if (!child._store || child._store.validated || child.key != null) { - return; - } + try { + var nextValue = latestGetSnapshot(); + return !objectIs(prevValue, nextValue); + } catch (error) { + return true; + } +} - if (typeof child._store !== "object") { - throw new Error( - "React Component in warnForMissingKey should have a _store. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - } // $FlowFixMe unable to narrow type from mixed to writable object +function forceStoreRerender(fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - child._store.validated = true; - var componentName = getComponentNameFromFiber(returnFiber) || "Component"; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } +} - if (ownerHasKeyUseWarning[componentName]) { - return; - } +function mountState(initialState) { + var hook = mountWorkInProgressHook(); - ownerHasKeyUseWarning[componentName] = true; + if (typeof initialState === "function") { + // $FlowFixMe: Flow doesn't like mixed types + initialState = initialState(); + } - error( - "Each child in a list should have a unique " + - '"key" prop. See https://reactjs.org/link/warning-keys for ' + - "more information." - ); + hook.memoizedState = hook.baseState = initialState; + var queue = { + pending: null, + lanes: NoLanes, + dispatch: null, + lastRenderedReducer: basicStateReducer, + lastRenderedState: initialState }; + hook.queue = queue; + var dispatch = (queue.dispatch = dispatchSetState.bind( + null, + currentlyRenderingFiber$1, + queue + )); + return [hook.memoizedState, dispatch]; } -function isReactClass(type) { - return type.prototype && type.prototype.isReactComponent; +function updateState(initialState) { + return updateReducer(basicStateReducer); } -function unwrapThenable(thenable) { - var index = thenableIndexCounter$1; - thenableIndexCounter$1 += 1; - - if (thenableState$1 === null) { - thenableState$1 = createThenableState(); - } - - return trackUsedThenable(thenableState$1, thenable, index); +function rerenderState(initialState) { + return rerenderReducer(basicStateReducer); } -function coerceRef(returnFiber, current, element) { - var mixedRef = element.ref; - - if ( - mixedRef !== null && - typeof mixedRef !== "function" && - typeof mixedRef !== "object" - ) { - { - if ( - // We warn in ReactElement.js if owner and self are equal for string refs - // because these cannot be automatically converted to an arrow function - // using a codemod. Therefore, we don't have to warn about string refs again. - !( - element._owner && - element._self && - element._owner.stateNode !== element._self - ) && // Will already throw with "Function components cannot have string refs" - !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" - !(typeof element.type === "function" && !isReactClass(element.type)) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" - element._owner - ) { - var componentName = - getComponentNameFromFiber(returnFiber) || "Component"; +function pushEffect(tag, create, destroy, deps) { + var effect = { + tag: tag, + create: create, + destroy: destroy, + deps: deps, + // Circular + next: null + }; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; - if (!didWarnAboutStringRefs[componentName]) { - error( - 'Component "%s" contains the string ref "%s". Support for string refs ' + - "will be removed in a future major release. We recommend using " + - "useRef() or createRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref", - componentName, - mixedRef - ); + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var lastEffect = componentUpdateQueue.lastEffect; - didWarnAboutStringRefs[componentName] = true; - } - } + if (lastEffect === null) { + componentUpdateQueue.lastEffect = effect.next = effect; + } else { + var firstEffect = lastEffect.next; + lastEffect.next = effect; + effect.next = firstEffect; + componentUpdateQueue.lastEffect = effect; } + } - if (element._owner) { - var owner = element._owner; - var inst; + return effect; +} - if (owner) { - var ownerFiber = owner; +var stackContainsErrorMessage = null; - if (ownerFiber.tag !== ClassComponent) { - throw new Error( - "Function components cannot have string refs. " + - "We recommend using useRef() instead. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-string-ref" - ); - } +function getCallerStackFrame() { + // eslint-disable-next-line react-internal/prod-error-codes + var stackFrames = new Error("Error message").stack.split("\n"); // Some browsers (e.g. Chrome) include the error message in the stack + // but others (e.g. Firefox) do not. - inst = ownerFiber.stateNode; - } + if (stackContainsErrorMessage === null) { + stackContainsErrorMessage = stackFrames[0].includes("Error message"); + } - if (!inst) { - throw new Error( - "Missing owner for string ref " + - mixedRef + - ". This error is likely caused by a " + - "bug in React. Please file an issue." - ); - } // Assigning this to a const so Flow knows it won't change in the closure + return stackContainsErrorMessage + ? stackFrames.slice(3, 4).join("\n") + : stackFrames.slice(2, 3).join("\n"); +} - var resolvedInst = inst; +function mountRef(initialValue) { + var hook = mountWorkInProgressHook(); - { - checkPropStringCoercion(mixedRef, "ref"); - } + if (enableUseRefAccessWarning) { + { + // Support lazy initialization pattern shown in docs. + // We need to store the caller stack frame so that we don't warn on subsequent renders. + var hasBeenInitialized = initialValue != null; + var lazyInitGetterStack = null; + var didCheckForLazyInit = false; // Only warn once per component+hook. - var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref + var didWarnAboutRead = false; + var didWarnAboutWrite = false; + var current = initialValue; + var ref = { + get current() { + if (!hasBeenInitialized) { + didCheckForLazyInit = true; + lazyInitGetterStack = getCallerStackFrame(); + } else if (currentlyRenderingFiber$1 !== null && !didWarnAboutRead) { + if ( + lazyInitGetterStack === null || + lazyInitGetterStack !== getCallerStackFrame() + ) { + didWarnAboutRead = true; - if ( - current !== null && - current.ref !== null && - typeof current.ref === "function" && - current.ref._stringRef === stringRef - ) { - return current.ref; - } + warn( + "%s: Unsafe read of a mutable value during render.\n\n" + + "Reading from a ref during render is only safe if:\n" + + "1. The ref value has not been updated, or\n" + + "2. The ref holds a lazily-initialized value that is only set once.\n", + getComponentNameFromFiber(currentlyRenderingFiber$1) || + "Unknown" + ); + } + } - var ref = function (value) { - var refs = resolvedInst.refs; + return current; + }, - if (value === null) { - delete refs[stringRef]; - } else { - refs[stringRef] = value; + set current(value) { + if (currentlyRenderingFiber$1 !== null && !didWarnAboutWrite) { + if (hasBeenInitialized || !didCheckForLazyInit) { + didWarnAboutWrite = true; + + warn( + "%s: Unsafe write of a mutable value during render.\n\n" + + "Writing to a ref during render is only safe if the ref holds " + + "a lazily-initialized value that is only set once.\n", + getComponentNameFromFiber(currentlyRenderingFiber$1) || + "Unknown" + ); + } + } + + hasBeenInitialized = true; + current = value; } }; - - ref._stringRef = stringRef; + Object.seal(ref); + hook.memoizedState = ref; return ref; - } else { - if (typeof mixedRef !== "string") { - throw new Error( - "Expected ref to be a function, a string, an object returned by React.createRef(), or null." - ); - } - - if (!element._owner) { - throw new Error( - "Element ref was specified as a string (" + - mixedRef + - ") but no owner was set. This could happen for one of" + - " the following reasons:\n" + - "1. You may be adding a ref to a function component\n" + - "2. You may be adding a ref to a component that was not created inside a component's render method\n" + - "3. You have multiple copies of React loaded\n" + - "See https://reactjs.org/link/refs-must-have-owner for more information." - ); - } } + } else { + var _ref2 = { + current: initialValue + }; + hook.memoizedState = _ref2; + return _ref2; } +} - return mixedRef; +function updateRef(initialValue) { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; } -function throwOnInvalidObjectType(returnFiber, newChild) { - // $FlowFixMe[method-unbinding] - var childString = Object.prototype.toString.call(newChild); - throw new Error( - "Objects are not valid as a React child (found: " + - (childString === "[object Object]" - ? "object with keys {" + Object.keys(newChild).join(", ") + "}" - : childString) + - "). " + - "If you meant to render a collection of children, use an array " + - "instead." +function mountEffectImpl(fiberFlags, hookFlags, create, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + currentlyRenderingFiber$1.flags |= fiberFlags; + hook.memoizedState = pushEffect( + HasEffect | hookFlags, + create, + undefined, + nextDeps ); } -function warnOnFunctionType(returnFiber) { - { - var componentName = getComponentNameFromFiber(returnFiber) || "Component"; +function updateEffectImpl(fiberFlags, hookFlags, create, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var destroy = undefined; // currentHook is null when rerendering after a render phase state update. - if (ownerHasFunctionTypeWarning[componentName]) { - return; + if (currentHook !== null) { + var prevEffect = currentHook.memoizedState; + destroy = prevEffect.destroy; + + if (nextDeps !== null) { + var prevDeps = prevEffect.deps; + + if (areHookInputsEqual(nextDeps, prevDeps)) { + hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps); + return; + } } + } - ownerHasFunctionTypeWarning[componentName] = true; + currentlyRenderingFiber$1.flags |= fiberFlags; + hook.memoizedState = pushEffect( + HasEffect | hookFlags, + create, + destroy, + nextDeps + ); +} - error( - "Functions are not valid as a React child. This may happen if " + - "you return a Component instead of from render. " + - "Or maybe you meant to call this function rather than return it." +function mountEffect(create, deps) { + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + mountEffectImpl( + MountPassiveDev | Passive$1 | PassiveStatic, + Passive, + create, + deps ); + } else { + mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); } } -function resolveLazy(lazyType) { - var payload = lazyType._payload; - var init = lazyType._init; - return init(payload); -} // 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 updateEffect(create, deps) { + updateEffectImpl(Passive$1, Passive, create, deps); +} -function createChildReconciler(shouldTrackSideEffects) { - function deleteChild(returnFiber, childToDelete) { - if (!shouldTrackSideEffects) { - // Noop. - return; - } +function useEffectEventImpl(payload) { + currentlyRenderingFiber$1.flags |= Update; + var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; - var deletions = returnFiber.deletions; + if (componentUpdateQueue === null) { + componentUpdateQueue = createFunctionComponentUpdateQueue(); + currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; + componentUpdateQueue.events = [payload]; + } else { + var events = componentUpdateQueue.events; - if (deletions === null) { - returnFiber.deletions = [childToDelete]; - returnFiber.flags |= ChildDeletion; + if (events === null) { + componentUpdateQueue.events = [payload]; } else { - deletions.push(childToDelete); + events.push(payload); } } +} - 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; +function mountEvent(callback) { + var hook = mountWorkInProgressHook(); + var ref = { + impl: callback + }; + hook.memoizedState = ref; // $FlowIgnore[incompatible-return] - while (childToDelete !== null) { - deleteChild(returnFiber, childToDelete); - childToDelete = childToDelete.sibling; + return function eventFn() { + if (isInvalidExecutionContextForEventFunction()) { + throw new Error( + "A function wrapped in useEffectEvent can't be called during rendering." + ); } - 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 - // instead. - var existingChildren = new Map(); - var existingChild = currentFirstChild; + return ref.impl.apply(undefined, arguments); + }; +} - while (existingChild !== null) { - if (existingChild.key !== null) { - existingChildren.set(existingChild.key, existingChild); - } else { - existingChildren.set(existingChild.index, existingChild); - } +function updateEvent(callback) { + var hook = updateWorkInProgressHook(); + var ref = hook.memoizedState; + useEffectEventImpl({ + ref: ref, + nextImpl: callback + }); // $FlowIgnore[incompatible-return] - existingChild = existingChild.sibling; + return function eventFn() { + if (isInvalidExecutionContextForEventFunction()) { + throw new Error( + "A function wrapped in useEffectEvent can't be called during rendering." + ); } - return existingChildren; - } + return ref.impl.apply(undefined, arguments); + }; +} - function useFiber(fiber, pendingProps) { - // 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); - clone.index = 0; - clone.sibling = null; - return clone; - } +function mountInsertionEffect(create, deps) { + mountEffectImpl(Update, Insertion, create, deps); +} - function placeChild(newFiber, lastPlacedIndex, newIndex) { - newFiber.index = newIndex; +function updateInsertionEffect(create, deps) { + return updateEffectImpl(Update, Insertion, create, deps); +} - if (!shouldTrackSideEffects) { - // During hydration, the useId algorithm needs to know which fibers are - // part of a list of children (arrays, iterators). - newFiber.flags |= Forked; - return lastPlacedIndex; - } +function mountLayoutEffect(create, deps) { + var fiberFlags = Update | LayoutStatic; - var current = newFiber.alternate; + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } - if (current !== null) { - var oldIndex = current.index; + return mountEffectImpl(fiberFlags, Layout, create, deps); +} - if (oldIndex < lastPlacedIndex) { - // This is a move. - newFiber.flags |= Placement | PlacementDEV; - return lastPlacedIndex; - } else { - // This item can stay in place. - return oldIndex; +function updateLayoutEffect(create, deps) { + return updateEffectImpl(Update, Layout, 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; + + { + if (!refObject.hasOwnProperty("current")) { + error( + "Expected useImperativeHandle() first argument to either be a " + + "ref callback or React.createRef() object. Instead received: %s.", + "an object with keys {" + Object.keys(refObject).join(", ") + "}" + ); } - } else { - // This is an insertion. - newFiber.flags |= Placement | PlacementDEV; - 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.flags |= Placement | PlacementDEV; - } + var _inst = create(); - return newFiber; + refObject.current = _inst; + return function () { + refObject.current = null; + }; } +} - function updateTextNode(returnFiber, current, textContent, lanes) { - if (current === null || current.tag !== HostText) { - // Insert - var created = createFiberFromText(textContent, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, textContent); - existing.return = returnFiber; - return existing; +function mountImperativeHandle(ref, create, deps) { + { + if (typeof create !== "function") { + error( + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" + ); } + } // TODO: If deps are provided, should we skip comparing the ref itself? + + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + var fiberFlags = Update | LayoutStatic; + + if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; } - function updateElement(returnFiber, current, element, lanes) { - var elementType = element.type; + mountEffectImpl( + fiberFlags, + Layout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} - if (elementType === REACT_FRAGMENT_TYPE) { - return updateFragment( - returnFiber, - current, - element.props.children, - lanes, - element.key +function updateImperativeHandle(ref, create, deps) { + { + if (typeof create !== "function") { + error( + "Expected useImperativeHandle() second argument to be a function " + + "that creates a handle. Instead received: %s.", + create !== null ? typeof create : "null" ); } + } // TODO: If deps are provided, should we skip comparing the ref itself? - if (current !== null) { - if ( - current.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === current.type) - ) { - // Move based on index - var existing = useFiber(current, element.props); - existing.ref = coerceRef(returnFiber, current, element); - existing.return = returnFiber; + var effectDeps = + deps !== null && deps !== undefined ? deps.concat([ref]) : null; + updateEffectImpl( + Update, + Layout, + imperativeHandleEffect.bind(null, create, ref), + effectDeps + ); +} - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } +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. +} - return existing; - } - } // Insert +var updateDebugValue = mountDebugValue; - var created = createFiberFromElement(element, returnFiber.mode, lanes); - created.ref = coerceRef(returnFiber, current, element); - created.return = returnFiber; - return created; - } +function mountCallback(callback, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + hook.memoizedState = [callback, nextDeps]; + return callback; +} - function updatePortal(returnFiber, current, portal, lanes) { - if ( - current === null || - current.tag !== HostPortal || - current.stateNode.containerInfo !== portal.containerInfo || - current.stateNode.implementation !== portal.implementation - ) { - // Insert - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, portal.children || []); - existing.return = returnFiber; - return existing; - } - } +function updateCallback(callback, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; - function updateFragment(returnFiber, current, fragment, lanes, key) { - if (current === null || current.tag !== Fragment) { - // Insert - var created = createFiberFromFragment( - fragment, - returnFiber.mode, - lanes, - key - ); - created.return = returnFiber; - return created; - } else { - // Update - var existing = useFiber(current, fragment); - existing.return = returnFiber; - return existing; + if (nextDeps !== null) { + var prevDeps = prevState[1]; + + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; } } - function createChild(returnFiber, newChild, lanes) { - if ( - (typeof newChild === "string" && newChild !== "") || - 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, lanes); - created.return = returnFiber; - return created; - } + hook.memoizedState = [callback, nextDeps]; + return callback; +} - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _created = createFiberFromElement( - newChild, - returnFiber.mode, - lanes - ); +function mountMemo(nextCreate, deps) { + var hook = mountWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; - _created.ref = coerceRef(returnFiber, null, newChild); - _created.return = returnFiber; - return _created; - } + if (shouldDoubleInvokeUserFnsInHooksDEV) { + nextCreate(); + } - case REACT_PORTAL_TYPE: { - var _created2 = createFiberFromPortal( - newChild, - returnFiber.mode, - lanes - ); + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - _created2.return = returnFiber; - return _created2; - } +function updateMemo(nextCreate, deps) { + var hook = updateWorkInProgressHook(); + var nextDeps = deps === undefined ? null : deps; + var prevState = hook.memoizedState; // Assume these are defined. If they're not, areHookInputsEqual will warn. - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return createChild(returnFiber, init(payload), lanes); - } - } + if (nextDeps !== null) { + var prevDeps = prevState[1]; - if (isArray(newChild) || getIteratorFn(newChild)) { - var _created3 = createFiberFromFragment( - newChild, - returnFiber.mode, - lanes, - null - ); + if (areHookInputsEqual(nextDeps, prevDeps)) { + return prevState[0]; + } + } - _created3.return = returnFiber; - return _created3; - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + if (shouldDoubleInvokeUserFnsInHooksDEV) { + nextCreate(); + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return createChild(returnFiber, unwrapThenable(thenable), lanes); - } + var nextValue = nextCreate(); + hook.memoizedState = [nextValue, nextDeps]; + return nextValue; +} - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return createChild( - returnFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } +function mountDeferredValue(value) { + var hook = mountWorkInProgressHook(); + hook.memoizedState = value; + return value; +} - throwOnInvalidObjectType(returnFiber, newChild); - } +function updateDeferredValue(value) { + var hook = updateWorkInProgressHook(); + var resolvedCurrentHook = currentHook; + var prevValue = resolvedCurrentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value); +} - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } +function rerenderDeferredValue(value) { + var hook = updateWorkInProgressHook(); - return null; + if (currentHook === null) { + // This is a rerender during a mount. + hook.memoizedState = value; + return value; + } else { + // This is a rerender during an update. + var prevValue = currentHook.memoizedState; + return updateDeferredValueImpl(hook, prevValue, value); } +} - function updateSlot(returnFiber, oldFiber, newChild, lanes) { - // Update the fiber if the keys match, otherwise return null. - var key = oldFiber !== null ? oldFiber.key : null; +function updateDeferredValueImpl(hook, prevValue, value) { + var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes$1); - if ( - (typeof newChild === "string" && newChild !== "") || - 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; - } + if (shouldDeferValue) { + // This is an urgent update. If the value has changed, keep using the + // previous value and spawn a deferred render to update it later. + if (!objectIs(value, prevValue)) { + // Schedule a deferred render + var deferredLane = claimNextTransitionLane(); + currentlyRenderingFiber$1.lanes = mergeLanes( + currentlyRenderingFiber$1.lanes, + deferredLane + ); + markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent + // from the latest value. The name "baseState" doesn't really match how we + // use it because we're reusing a state hook field instead of creating a + // new one. - return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); - } + hook.baseState = true; + } // Reuse the previous value - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - if (newChild.key === key) { - return updateElement(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } + return prevValue; + } else { + // This is not an urgent update, so we can use the latest value regardless + // of what it is. No need to defer it. + // However, if we're currently inside a spawned render, then we need to mark + // this as an update to prevent the fiber from bailing out. + // + // `baseState` is true when the current value is different from the rendered + // value. The name doesn't really match how we use it because we're reusing + // a state hook field instead of creating a new one. + if (hook.baseState) { + // Flip this back to false. + hook.baseState = false; + markWorkInProgressReceivedUpdate(); + } - case REACT_PORTAL_TYPE: { - if (newChild.key === key) { - return updatePortal(returnFiber, oldFiber, newChild, lanes); - } else { - return null; - } - } + hook.memoizedState = value; + return value; + } +} - case REACT_LAZY_TYPE: { - var payload = newChild._payload; - var init = newChild._init; - return updateSlot(returnFiber, oldFiber, init(payload), lanes); - } - } +function startTransition(setPending, callback, options) { + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority( + higherEventPriority(previousPriority, ContinuousEventPriority) + ); + setPending(true); + var prevTransition = ReactCurrentBatchConfig$3.transition; + ReactCurrentBatchConfig$3.transition = {}; + var currentTransition = ReactCurrentBatchConfig$3.transition; - if (isArray(newChild) || getIteratorFn(newChild)) { - if (key !== null) { - return null; - } + if (enableTransitionTracing) { + if (options !== undefined && options.name !== undefined) { + ReactCurrentBatchConfig$3.transition.name = options.name; + ReactCurrentBatchConfig$3.transition.startTime = now$1(); + } + } - return updateFragment(returnFiber, oldFiber, newChild, lanes, null); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + { + ReactCurrentBatchConfig$3.transition._updatedFibers = new Set(); + } - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateSlot( - returnFiber, - oldFiber, - unwrapThenable(thenable), - lanes - ); - } + try { + setPending(false); + callback(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig$3.transition = prevTransition; - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return updateSlot( - returnFiber, - oldFiber, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + { + if (prevTransition === null && currentTransition._updatedFibers) { + var updatedFibersCount = currentTransition._updatedFibers.size; - throwOnInvalidObjectType(returnFiber, newChild); - } + currentTransition._updatedFibers.clear(); - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); + if (updatedFibersCount > 10) { + warn( + "Detected a large number of updates inside startTransition. " + + "If this is due to a subscription please re-write it to use React provided hooks. " + + "Otherwise concurrent mode guarantees are off the table." + ); + } } } - - return null; } +} - function updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChild, - lanes - ) { - if ( - (typeof newChild === "string" && newChild !== "") || - 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, lanes); - } +function mountTransition() { + var _mountState = mountState(false), + isPending = _mountState[0], + setPending = _mountState[1]; // The `start` method never changes. - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: { - var _matchedFiber = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + var start = startTransition.bind(null, setPending); + var hook = mountWorkInProgressHook(); + hook.memoizedState = start; + return [isPending, start]; +} - return updateElement(returnFiber, _matchedFiber, newChild, lanes); - } +function updateTransition() { + var _updateState = updateState(), + isPending = _updateState[0]; - case REACT_PORTAL_TYPE: { - var _matchedFiber2 = - existingChildren.get( - newChild.key === null ? newIdx : newChild.key - ) || null; + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + return [isPending, start]; +} - return updatePortal(returnFiber, _matchedFiber2, newChild, lanes); - } +function rerenderTransition() { + var _rerenderState = rerenderState(), + isPending = _rerenderState[0]; - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - init(payload), - lanes - ); - } + var hook = updateWorkInProgressHook(); + var start = hook.memoizedState; + return [isPending, start]; +} - if (isArray(newChild) || getIteratorFn(newChild)) { - var _matchedFiber3 = existingChildren.get(newIdx) || null; +function mountId() { + var hook = mountWorkInProgressHook(); + var root = getWorkInProgressRoot(); // TODO: In Fizz, id generation is specific to each server config. Maybe we + // should do this in Fiber, too? Deferring this decision for now because + // there's no other place to store the prefix except for an internal field on + // the public createRoot object, which the fiber tree does not currently have + // a reference to. - return updateFragment( - returnFiber, - _matchedFiber3, - newChild, - lanes, - null - ); - } // Usable node types - // - // Unwrap the inner value and recursively call this function again. + var identifierPrefix = root.identifierPrefix; + var id; - if (typeof newChild.then === "function") { - var thenable = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - unwrapThenable(thenable), - lanes - ); - } + if (getIsHydrating()) { + var treeId = getTreeId(); // Use a captial R prefix for server-generated ids. - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return updateFromMap( - existingChildren, - returnFiber, - newIdx, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); - } + id = ":" + identifierPrefix + "R" + treeId; // Unless this is the first id at this level, append a number at the end + // that represents the position of this useId hook among all the useId + // hooks for this fiber. - throwOnInvalidObjectType(returnFiber, newChild); - } + var localId = localIdCounter++; - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } + if (localId > 0) { + id += "H" + localId.toString(32); } - return null; + id += ":"; + } else { + // Use a lowercase r prefix for client-generated ids. + var globalClientId = globalClientIdCounter++; + id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":"; } - /** - * Warns if there is a duplicate or missing key - */ - function warnOnInvalidKey(child, knownKeys, returnFiber) { - { - if (typeof child !== "object" || child === null) { - return knownKeys; - } + hook.memoizedState = id; + return id; +} - switch (child.$$typeof) { - case REACT_ELEMENT_TYPE: - case REACT_PORTAL_TYPE: - warnForMissingKey(child, returnFiber); - var key = child.key; +function updateId() { + var hook = updateWorkInProgressHook(); + var id = hook.memoizedState; + return id; +} - if (typeof key !== "string") { - break; - } +function mountRefresh() { + var hook = mountWorkInProgressHook(); + var refresh = (hook.memoizedState = refreshCache.bind( + null, + currentlyRenderingFiber$1 + )); + return refresh; +} - if (knownKeys === null) { - knownKeys = new Set(); - knownKeys.add(key); - break; - } +function updateRefresh() { + var hook = updateWorkInProgressHook(); + return hook.memoizedState; +} - if (!knownKeys.has(key)) { - knownKeys.add(key); - break; - } +function refreshCache(fiber, seedKey, seedValue) { + // TODO: Consider warning if the refresh is at discrete priority, or if we + // otherwise suspect that it wasn't batched properly. - error( - "Encountered two children with the same key, `%s`. " + - "Keys should be unique so that components maintain their identity " + - "across updates. Non-unique keys may cause children to be " + - "duplicated and/or omitted — the behavior is unsupported and " + - "could change in a future version.", - key - ); + var provider = fiber.return; - break; + while (provider !== null) { + switch (provider.tag) { + case CacheComponent: + case HostRoot: { + // Schedule an update on the cache boundary to trigger a refresh. + var lane = requestUpdateLane(provider); + var refreshUpdate = createUpdate(lane); + var root = enqueueUpdate(provider, refreshUpdate, lane); - case REACT_LAZY_TYPE: - var payload = child._payload; - var init = child._init; - warnOnInvalidKey(init(payload), knownKeys, returnFiber); - break; - } - } + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, provider, lane, eventTime); + entangleTransitions(root, provider, lane); + } // TODO: If a refresh never commits, the new cache created here must be + // released. A simple case is start refreshing a cache boundary, but then + // unmount that boundary before the refresh completes. - return knownKeys; - } + var seededCache = createCache(); - function reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChildren, - lanes - ) { - // 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. - { - // First, validate keys. - var knownKeys = null; + if (seedKey !== null && seedKey !== undefined && root !== null) { + { + // Seed the cache with the value passed by the caller. This could be + // from a server mutation, or it could be a streaming response. + seededCache.data.set(seedKey, seedValue); + } + } - for (var i = 0; i < newChildren.length; i++) { - var child = newChildren[i]; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); + var payload = { + cache: seededCache + }; + refreshUpdate.payload = payload; + return; } } - 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; - } + provider = provider.return; + } // TODO: Warn if unmounted? +} - var newFiber = updateSlot( - returnFiber, - oldFiber, - newChildren[newIdx], - lanes +function dispatchReducerAction(fiber, queue, action) { + { + if (typeof arguments[3] === "function") { + error( + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." ); - - 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); + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; - if (getIsHydrating()) { - var numberOfForks = newIdx; - pushTreeFork(returnFiber, numberOfForks); - } + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - return resultingFirstChild; + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitionUpdate(root, queue, lane); } + } - 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], lanes); + markUpdateInDevTools(fiber, lane, action); +} - if (_newFiber === null) { - continue; - } +function dispatchSetState(fiber, queue, action) { + { + if (typeof arguments[3] === "function") { + error( + "State updates from the useState() and useReducer() Hooks don't support the " + + "second callback argument. To execute a side effect after " + + "rendering, declare it in the component body with useEffect()." + ); + } + } - lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); + var lane = requestUpdateLane(fiber); + var update = { + lane: lane, + action: action, + hasEagerState: false, + eagerState: null, + next: null + }; - if (previousNewFiber === null) { - // TODO: Move out of the loop. This only happens for the first run. - resultingFirstChild = _newFiber; - } else { - previousNewFiber.sibling = _newFiber; - } + if (isRenderPhaseUpdate(fiber)) { + enqueueRenderPhaseUpdate(queue, update); + } else { + var alternate = fiber.alternate; - previousNewFiber = _newFiber; - } + if ( + fiber.lanes === NoLanes && + (alternate === null || alternate.lanes === NoLanes) + ) { + // 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 (getIsHydrating()) { - var _numberOfForks = newIdx; - pushTreeFork(returnFiber, _numberOfForks); - } + if (lastRenderedReducer !== null) { + var prevDispatcher; - return resultingFirstChild; - } // Add all children to a key map for quick lookups. + { + prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; + } - var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves. + 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. - for (; newIdx < newChildren.length; newIdx++) { - var _newFiber2 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - newChildren[newIdx], - lanes - ); + update.hasEagerState = true; + update.eagerState = eagerState; - if (_newFiber2 !== null) { - 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 - ); + if (objectIs(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. + // TODO: Do we still need to entangle transitions in this case? + enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update); + return; + } + } catch (error) { + // Suppress the error. It will throw again in the render phase. + } finally { + { + ReactCurrentDispatcher$1.current = prevDispatcher; } } - - 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); - }); - } + var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); - if (getIsHydrating()) { - var _numberOfForks2 = newIdx; - pushTreeFork(returnFiber, _numberOfForks2); + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitionUpdate(root, queue, lane); } - - return resultingFirstChild; } - function reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChildrenIterable, - lanes - ) { - // This is the same implementation as reconcileChildrenArray(), - // but using the iterator instead. - var iteratorFn = getIteratorFn(newChildrenIterable); + markUpdateInDevTools(fiber, lane, action); +} - if (typeof iteratorFn !== "function") { - throw new Error( - "An object is not an iterable. This error is likely caused by a bug in " + - "React. Please file an issue." - ); - } +function isRenderPhaseUpdate(fiber) { + var alternate = fiber.alternate; + return ( + fiber === currentlyRenderingFiber$1 || + (alternate !== null && alternate === currentlyRenderingFiber$1) + ); +} - { - // We don't support rendering Generators because it's a mutation. - // See https://github.com/facebook/react/issues/12995 - if ( - typeof Symbol === "function" && // $FlowFixMe Flow doesn't know about toStringTag - newChildrenIterable[Symbol.toStringTag] === "Generator" - ) { - if (!didWarnAboutGenerators) { - error( - "Using Generators as children is unsupported and will likely yield " + - "unexpected results because enumerating a generator mutates it. " + - "You may convert it to an array with `Array.from()` or the " + - "`[...spread]` operator before rendering. Keep in mind " + - "you might need to polyfill these features for older browsers." - ); - } +function enqueueRenderPhaseUpdate(queue, update) { + // 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. + didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = + true; + var pending = queue.pending; - didWarnAboutGenerators = true; - } // Warn about using Maps as children + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - if (newChildrenIterable.entries === iteratorFn) { - if (!didWarnAboutMaps) { - error( - "Using Maps as children is not supported. " + - "Use an array of keyed ReactElements instead." - ); - } + queue.pending = update; +} // TODO: Move to ReactFiberConcurrentUpdates? - didWarnAboutMaps = true; - } // First, validate keys. - // We'll get a different iterator later for the main pass. +function entangleTransitionUpdate(root, queue, lane) { + if (isTransitionLane(lane)) { + var queueLanes = queue.lanes; // If any entangled lanes are no longer pending on the root, then they + // must have finished. We can remove them from the shared queue, which + // represents a superset of the actually pending lanes. In some cases we + // may entangle more than we need to, but that's OK. In fact it's worse if + // we *don't* entangle when we should. - var _newChildren = iteratorFn.call(newChildrenIterable); + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - if (_newChildren) { - var knownKeys = null; + var newQueueLanes = mergeLanes(queueLanes, lane); + queue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - var _step = _newChildren.next(); + markRootEntangled(root, newQueueLanes); + } +} - for (; !_step.done; _step = _newChildren.next()) { - var child = _step.value; - knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber); - } +function markUpdateInDevTools(fiber, lane, action) { + { + if (enableDebugTracing) { + if (fiber.mode & DebugTracingMode) { + var name = getComponentNameFromFiber(fiber) || "Unknown"; + logStateUpdateScheduled(name, lane, action); } } + } - var newChildren = iteratorFn.call(newChildrenIterable); + if (enableSchedulingProfiler) { + markStateUpdateScheduled(fiber, lane); + } +} - if (newChildren == null) { - throw new Error("An iterable object provided no iterator."); - } +var ContextOnlyDispatcher = { + readContext: readContext, + useCallback: throwInvalidHookError, + useContext: throwInvalidHookError, + useEffect: throwInvalidHookError, + useImperativeHandle: throwInvalidHookError, + useInsertionEffect: throwInvalidHookError, + useLayoutEffect: throwInvalidHookError, + useMemo: throwInvalidHookError, + useReducer: throwInvalidHookError, + useRef: throwInvalidHookError, + useState: throwInvalidHookError, + useDebugValue: throwInvalidHookError, + useDeferredValue: throwInvalidHookError, + useTransition: throwInvalidHookError, + useMutableSource: throwInvalidHookError, + useSyncExternalStore: throwInvalidHookError, + useId: throwInvalidHookError +}; - 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, lanes); +{ + ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; +} - 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; - } +{ + ContextOnlyDispatcher.use = throwInvalidHookError; +} - break; - } +{ + ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; +} - 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); - } - } +{ + ContextOnlyDispatcher.useEffectEvent = throwInvalidHookError; +} - lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); +var HooksDispatcherOnMountInDEV = null; +var HooksDispatcherOnMountWithHookTypesInDEV = null; +var HooksDispatcherOnUpdateInDEV = null; +var HooksDispatcherOnRerenderInDEV = null; +var InvalidNestedHooksDispatcherOnMountInDEV = null; +var InvalidNestedHooksDispatcherOnUpdateInDEV = null; +var InvalidNestedHooksDispatcherOnRerenderInDEV = null; - 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; - } +{ + var warnInvalidContextAccess = function () { + error( + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + }; - previousNewFiber = newFiber; - oldFiber = nextOldFiber; - } + var warnInvalidHookAccess = function () { + error( + "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + + "You can only call Hooks at the top level of your React function. " + + "For more information, see " + + "https://reactjs.org/link/rules-of-hooks" + ); + }; - if (step.done) { - // We've reached the end of the new children. We can delete the rest. - deleteRemainingChildren(returnFiber, oldFiber); + HooksDispatcherOnMountInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + mountHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + return mountLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + mountHookTypesDev(); + checkDepsAreArrayDev(deps); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (getIsHydrating()) { - var numberOfForks = newIdx; - pushTreeFork(returnFiber, numberOfForks); + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - 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, lanes); - - 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; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (getIsHydrating()) { - var _numberOfForks3 = newIdx; - pushTreeFork(returnFiber, _numberOfForks3); + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + mountHookTypesDev(); + return mountDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + mountHookTypesDev(); + return mountTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + mountHookTypesDev(); + return mountMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + mountHookTypesDev(); + return mountId(); + } + }; - 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. + { + HooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = "useCacheRefresh"; + mountHookTypesDev(); + return mountRefresh(); + }; + } - for (; !step.done; newIdx++, step = newChildren.next()) { - var _newFiber4 = updateFromMap( - existingChildren, - returnFiber, - newIdx, - step.value, - lanes - ); + { + HooksDispatcherOnMountInDEV.use = use; + } - 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 - ); - } - } + { + HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; + } - lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); + { + HooksDispatcherOnMountInDEV.useEffectEvent = function useEffectEvent( + callback + ) { + currentHookNameInDev = "useEffectEvent"; + mountHookTypesDev(); + return mountEvent(callback); + }; + } - if (previousNewFiber === null) { - resultingFirstChild = _newFiber4; - } else { - previousNewFiber.sibling = _newFiber4; - } + HooksDispatcherOnMountWithHookTypesInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + updateHookTypesDev(); + return mountInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - previousNewFiber = _newFiber4; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - 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); - }); - } + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (getIsHydrating()) { - var _numberOfForks4 = newIdx; - pushTreeFork(returnFiber, _numberOfForks4); + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + updateHookTypesDev(); + return mountDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + updateHookTypesDev(); + return mountTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + updateHookTypesDev(); + return mountMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + updateHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + updateHookTypesDev(); + return mountId(); } + }; - return resultingFirstChild; + { + HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = + function useCacheRefresh() { + currentHookNameInDev = "useCacheRefresh"; + updateHookTypesDev(); + return mountRefresh(); + }; } - function reconcileSingleTextNode( - returnFiber, - currentFirstChild, - textContent, - lanes - ) { - // 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); - 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, lanes); - created.return = returnFiber; - return created; + { + HooksDispatcherOnMountWithHookTypesInDEV.use = use; } - function reconcileSingleElement( - returnFiber, - currentFirstChild, - element, - lanes - ) { - var key = element.key; - var child = currentFirstChild; + { + HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; + } - 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) { - var elementType = element.type; + { + HooksDispatcherOnMountWithHookTypesInDEV.useEffectEvent = + function useEffectEvent(callback) { + currentHookNameInDev = "useEffectEvent"; + updateHookTypesDev(); + return mountEvent(callback); + }; + } - if (elementType === REACT_FRAGMENT_TYPE) { - if (child.tag === Fragment) { - deleteRemainingChildren(returnFiber, child.sibling); - var existing = useFiber(child, element.props.children); - existing.return = returnFiber; + HooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - { - existing._debugSource = element._source; - existing._debugOwner = element._owner; - } + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - return existing; - } - } else { - if ( - child.elementType === elementType || // Keep this check inline so it only runs on the false path: - isCompatibleFamilyForHotReloading(child, element) || // Lazy types should reconcile their resolved type. - // We need to do this after the Hot Reloading check above, - // because hot reloading has different semantics than prod because - // it doesn't resuspend. So we can't let the call below suspend. - (typeof elementType === "object" && - elementType !== null && - elementType.$$typeof === REACT_LAZY_TYPE && - resolveLazy(elementType) === child.type) - ) { - deleteRemainingChildren(returnFiber, child.sibling); - - var _existing = useFiber(child, element.props); - - _existing.ref = coerceRef(returnFiber, child, element); - _existing.return = returnFiber; - - { - _existing._debugSource = element._source; - _existing._debugOwner = element._owner; - } - - return _existing; - } - } // Didn't match. - - deleteRemainingChildren(returnFiber, child); - break; - } else { - deleteChild(returnFiber, child); + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - child = child.sibling; - } - - if (element.type === REACT_FRAGMENT_TYPE) { - var created = createFiberFromFragment( - element.props.children, - returnFiber.mode, - lanes, - element.key - ); - created.return = returnFiber; - return created; - } else { - var _created4 = createFiberFromElement(element, returnFiber.mode, lanes); - - _created4.ref = coerceRef(returnFiber, currentFirstChild, element); - _created4.return = returnFiber; - return _created4; - } - } - - function reconcileSinglePortal( - returnFiber, - currentFirstChild, - portal, - lanes - ) { - 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 || []); - existing.return = returnFiber; - return existing; - } else { - deleteRemainingChildren(returnFiber, child); - break; - } - } else { - deleteChild(returnFiber, child); + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - - child = child.sibling; + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + updateHookTypesDev(); + return updateDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + updateHookTypesDev(); + return updateTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + updateHookTypesDev(); + return updateId(); } + }; - var created = createFiberFromPortal(portal, returnFiber.mode, lanes); - 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 reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - // 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. - // TODO: Let's use recursion like we do for Usable nodes? - var isUnkeyedTopLevelFragment = - typeof newChild === "object" && - newChild !== null && - newChild.type === REACT_FRAGMENT_TYPE && - newChild.key === null; - - if (isUnkeyedTopLevelFragment) { - newChild = newChild.props.children; - } // Handle object types + { + HooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { + currentHookNameInDev = "useCacheRefresh"; + updateHookTypesDev(); + return updateRefresh(); + }; + } - if (typeof newChild === "object" && newChild !== null) { - switch (newChild.$$typeof) { - case REACT_ELEMENT_TYPE: - return placeSingleChild( - reconcileSingleElement( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + { + HooksDispatcherOnUpdateInDEV.use = use; + } - case REACT_PORTAL_TYPE: - return placeSingleChild( - reconcileSinglePortal( - returnFiber, - currentFirstChild, - newChild, - lanes - ) - ); + { + HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; + } - case REACT_LAZY_TYPE: - var payload = newChild._payload; - var init = newChild._init; // TODO: This function is supposed to be non-recursive. + { + HooksDispatcherOnUpdateInDEV.useEffectEvent = function useEffectEvent( + callback + ) { + currentHookNameInDev = "useEffectEvent"; + updateHookTypesDev(); + return updateEvent(callback); + }; + } - return reconcileChildFibers( - returnFiber, - currentFirstChild, - init(payload), - lanes - ); - } + HooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnRerenderInDEV; - if (isArray(newChild)) { - return reconcileChildrenArray( - returnFiber, - currentFirstChild, - newChild, - lanes - ); + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnRerenderInDEV; - if (getIteratorFn(newChild)) { - return reconcileChildrenIterator( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - } // Usables are a valid React node type. When React encounters a Usable in - // a child position, it unwraps it using the same algorithm as `use`. For - // example, for promises, React will throw an exception to unwind the - // stack, then replay the component once the promise resolves. - // - // A difference from `use` is that React will keep unwrapping the value - // until it reaches a non-Usable type. - // - // e.g. Usable>> should resolve to T - // - // The structure is a bit unfortunate. Ideally, we shouldn't need to - // replay the entire begin phase of the parent fiber in order to reconcile - // the children again. This would require a somewhat significant refactor, - // because reconcilation happens deep within the begin phase, and - // depending on the type of work, not always at the end. We should - // consider as an future improvement. - - if (typeof newChild.then === "function") { - var thenable = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - unwrapThenable(thenable), - lanes - ); + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnRerenderInDEV; - if ( - newChild.$$typeof === REACT_CONTEXT_TYPE || - newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE - ) { - var context = newChild; - return reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - readContextDuringReconcilation(returnFiber, context, lanes), - lanes - ); + try { + return rerenderState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - - throwOnInvalidObjectType(returnFiber, newChild); - } - - if ( - (typeof newChild === "string" && newChild !== "") || - typeof newChild === "number" - ) { - return placeSingleChild( - reconcileSingleTextNode( - returnFiber, - currentFirstChild, - "" + newChild, - lanes - ) - ); + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + updateHookTypesDev(); + return rerenderDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + updateHookTypesDev(); + return rerenderTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + updateHookTypesDev(); + return updateId(); } + }; - { - if (typeof newChild === "function") { - warnOnFunctionType(returnFiber); - } - } // Remaining cases are all treated as empty. - - return deleteRemainingChildren(returnFiber, currentFirstChild); - } - - function reconcileChildFibers( - returnFiber, - currentFirstChild, - newChild, - lanes - ) { - // This indirection only exists so we can reset `thenableState` at the end. - // It should get inlined by Closure. - thenableIndexCounter$1 = 0; - var firstChildFiber = reconcileChildFibersImpl( - returnFiber, - currentFirstChild, - newChild, - lanes - ); - thenableState$1 = null; // Don't bother to reset `thenableIndexCounter` to 0 because it always gets - // set at the beginning. - - return firstChildFiber; + { + HooksDispatcherOnRerenderInDEV.useCacheRefresh = + function useCacheRefresh() { + currentHookNameInDev = "useCacheRefresh"; + updateHookTypesDev(); + return updateRefresh(); + }; } - return reconcileChildFibers; -} - -var reconcileChildFibers = createChildReconciler(true); -var mountChildFibers = createChildReconciler(false); -function resetChildReconcilerOnUnwind() { - // On unwind, clear any pending thenables that were used. - thenableState$1 = null; - thenableIndexCounter$1 = 0; -} -function cloneChildFibers(current, workInProgress) { - if (current !== null && workInProgress.child !== current.child) { - throw new Error("Resuming work not yet implemented."); + { + HooksDispatcherOnRerenderInDEV.use = use; } - if (workInProgress.child === null) { - return; + { + HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; } - var currentChild = workInProgress.child; - var newChild = createWorkInProgress(currentChild, currentChild.pendingProps); - workInProgress.child = newChild; - newChild.return = workInProgress; - - while (currentChild.sibling !== null) { - currentChild = currentChild.sibling; - newChild = newChild.sibling = createWorkInProgress( - currentChild, - currentChild.pendingProps - ); - newChild.return = workInProgress; + { + HooksDispatcherOnRerenderInDEV.useEffectEvent = function useEffectEvent( + callback + ) { + currentHookNameInDev = "useEffectEvent"; + updateHookTypesDev(); + return updateEvent(callback); + }; } - newChild.sibling = null; -} // Reset a workInProgress child set to prepare it for a second pass. - -function resetChildFibers(workInProgress, lanes) { - var child = workInProgress.child; + InvalidNestedHooksDispatcherOnMountInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - while (child !== null) { - resetWorkInProgress(child, lanes); - child = child.sibling; - } -} - -// TODO: This isn't being used yet, but it's intended to replace the -// InvisibleParentContext that is currently managed by SuspenseContext. - -var currentTreeHiddenStackCursor = createCursor(null); -var prevRenderLanesStackCursor = createCursor(NoLanes); -function pushHiddenContext(fiber, context) { - var prevRenderLanes = getRenderLanes(); - push(prevRenderLanesStackCursor, prevRenderLanes, fiber); - push(currentTreeHiddenStackCursor, context, fiber); // When rendering a subtree that's currently hidden, we must include all - // lanes that would have rendered if the hidden subtree hadn't been deferred. - // That is, in order to reveal content from hidden -> visible, we must commit - // all the updates that we skipped when we originally hid the tree. - - setRenderLanes(mergeLanes(prevRenderLanes, context.baseLanes)); -} -function reuseHiddenContextOnStack(fiber) { - // This subtree is not currently hidden, so we don't need to add any lanes - // to the render lanes. But we still need to push something to avoid a - // context mismatch. Reuse the existing context on the stack. - push(prevRenderLanesStackCursor, getRenderLanes(), fiber); - push( - currentTreeHiddenStackCursor, - currentTreeHiddenStackCursor.current, - fiber - ); -} -function popHiddenContext(fiber) { - // Restore the previous render lanes from the stack - setRenderLanes(prevRenderLanesStackCursor.current); - pop(currentTreeHiddenStackCursor, fiber); - pop(prevRenderLanesStackCursor, fiber); -} -function isCurrentTreeHidden() { - return currentTreeHiddenStackCursor.current !== null; -} - -// suspends, i.e. it's the nearest `catch` block on the stack. - -var suspenseHandlerStackCursor = createCursor(null); // Represents the outermost boundary that is not visible in the current tree. -// Everything above this is the "shell". When this is null, it means we're -// rendering in the shell of the app. If it's non-null, it means we're rendering -// deeper than the shell, inside a new tree that wasn't already visible. -// -// The main way we use this concept is to determine whether showing a fallback -// would result in a desirable or undesirable loading state. Activing a fallback -// in the shell is considered an undersirable loading state, because it would -// mean hiding visible (albeit stale) content in the current tree — we prefer to -// show the stale content, rather than switch to a fallback. But showing a -// fallback in a new tree is fine, because there's no stale content to -// prefer instead. - -var shellBoundary = null; -function getShellBoundary() { - return shellBoundary; -} -function pushPrimaryTreeSuspenseHandler(handler) { - // TODO: Pass as argument - var current = handler.alternate; - var props = handler.pendingProps; // Experimental feature: Some Suspense boundaries are marked as having an - // undesirable fallback state. These have special behavior where we only - // activate the fallback if there's no other boundary on the stack that we can - // use instead. - - if ( - props.unstable_avoidThisFallback === true && // If an avoided boundary is already visible, it behaves identically to - // a regular Suspense boundary. - (current === null || isCurrentTreeHidden()) - ) { - if (shellBoundary === null) { - // We're rendering in the shell. There's no parent Suspense boundary that - // can provide a desirable fallback state. We'll use this boundary. - push(suspenseHandlerStackCursor, handler, handler); // However, because this is not a desirable fallback, the children are - // still considered part of the shell. So we intentionally don't assign - // to `shellBoundary`. - } else { - // There's already a parent Suspense boundary that can provide a desirable - // fallback state. Prefer that one. - var handlerOnStack = suspenseHandlerStackCursor.current; - push(suspenseHandlerStackCursor, handlerOnStack, handler); - } - - return; - } // TODO: If the parent Suspense handler already suspended, there's no reason - // to push a nested Suspense handler, because it will get replaced by the - // outer fallback, anyway. Consider this as a future optimization. - - push(suspenseHandlerStackCursor, handler, handler); - - if (shellBoundary === null) { - if (current === null || isCurrentTreeHidden()) { - // This boundary is not visible in the current UI. - shellBoundary = handler; - } else { - var prevState = current.memoizedState; - - if (prevState !== null) { - // This boundary is showing a fallback in the current UI. - shellBoundary = handler; + try { + return mountMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } - } -} -function pushFallbackTreeSuspenseHandler(fiber) { - // We're about to render the fallback. If something in the fallback suspends, - // it's akin to throwing inside of a `catch` block. This boundary should not - // capture. Reuse the existing handler on the stack. - reuseSuspenseHandlerOnStack(fiber); -} -function pushOffscreenSuspenseHandler(fiber) { - if (fiber.tag === OffscreenComponent) { - push(suspenseHandlerStackCursor, fiber, fiber); - - if (shellBoundary !== null); - else { - var current = fiber.alternate; + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (current !== null) { - var prevState = current.memoizedState; + try { + return mountReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountRef(initialValue); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + mountHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnMountInDEV; - if (prevState !== null) { - // This is the first boundary in the stack that's already showing - // a fallback. So everything outside is considered the shell. - shellBoundary = fiber; - } + try { + return mountState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountId(); } - } else { - // This is a LegacyHidden component. - reuseSuspenseHandlerOnStack(fiber); - } -} -function reuseSuspenseHandlerOnStack(fiber) { - push(suspenseHandlerStackCursor, getSuspenseHandler(), fiber); -} -function getSuspenseHandler() { - return suspenseHandlerStackCursor.current; -} -function popSuspenseHandler(fiber) { - pop(suspenseHandlerStackCursor, fiber); + }; - if (shellBoundary === fiber) { - // Popping back into the shell. - shellBoundary = null; + { + InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = + function useCacheRefresh() { + currentHookNameInDev = "useCacheRefresh"; + mountHookTypesDev(); + return mountRefresh(); + }; } -} // SuspenseList context -// TODO: Move to a separate module? We may change the SuspenseList -// implementation to hide/show in the commit phase, anyway. - -var DefaultSuspenseContext = 0; -var SubtreeSuspenseContextMask = 1; // ForceSuspenseFallback can be used by SuspenseList to force newly added -// items into their fallback state during one of the render passes. - -var ForceSuspenseFallback = 2; -var suspenseStackCursor = createCursor(DefaultSuspenseContext); -function hasSuspenseListContext(parentContext, flag) { - return (parentContext & flag) !== 0; -} -function setDefaultShallowSuspenseListContext(parentContext) { - return parentContext & SubtreeSuspenseContextMask; -} -function setShallowSuspenseListContext(parentContext, shallowContext) { - return (parentContext & SubtreeSuspenseContextMask) | shallowContext; -} -function pushSuspenseListContext(fiber, newContext) { - push(suspenseStackCursor, newContext, fiber); -} -function popSuspenseListContext(fiber) { - pop(suspenseStackCursor, fiber); -} -// A non-null SuspenseState means that it is blocked for one reason or another. -// - A non-null dehydrated field means it's blocked pending hydration. -// - A non-null dehydrated field can use isSuspenseInstancePending or -// isSuspenseInstanceFallback to query the reason for being dehydrated. -// - A null dehydrated field means it's blocked by something suspending and -// we're currently showing a fallback instead. + { + InvalidNestedHooksDispatcherOnMountInDEV.use = function (usable) { + warnInvalidHookAccess(); + return use(usable); + }; + } -function findFirstSuspended(row) { - var node = row; + { + InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + { + InvalidNestedHooksDispatcherOnMountInDEV.useEffectEvent = + function useEffectEvent(callback) { + currentHookNameInDev = "useEffectEvent"; + warnInvalidHookAccess(); + mountHookTypesDev(); + return mountEvent(callback); + }; + } - if (state !== null) { - var dehydrated = state.dehydrated; + InvalidNestedHooksDispatcherOnUpdateInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - if ( - dehydrated === null || - isSuspenseInstancePending(dehydrated) || - isSuspenseInstanceFallback(dehydrated) - ) { - return node; - } + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } else if ( - node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't - // keep track of whether it suspended or not. - node.memoizedProps.revealOrder !== undefined - ) { - var didSuspend = (node.flags & DidCapture) !== NoFlags$1; + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - if (didSuspend) { - return node; + try { + return updateReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } - - if (node === row) { - return null; - } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; - while (node.sibling === null) { - if (node.return === null || node.return === row) { - return null; + try { + return updateState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } - - node = node.return; + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); } + }; - node.sibling.return = node.return; - node = node.sibling; + { + InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = + function useCacheRefresh() { + currentHookNameInDev = "useCacheRefresh"; + updateHookTypesDev(); + return updateRefresh(); + }; } - return null; -} - -var NoFlags = - /* */ - 0; // Represents whether effect should fire. - -var HasEffect = - /* */ - 1; // Represents the phase in which the effect (not the clean-up) fires. - -var Insertion = - /* */ - 2; -var Layout = - /* */ - 4; -var Passive = - /* */ - 8; - -// and should be reset before starting a new render. -// This tracks which mutable sources need to be reset after a render. - -var workInProgressSources = []; -var rendererSigil$1; - -{ - // Used to detect multiple renderers using the same mutable source. - rendererSigil$1 = {}; -} - -function markSourceAsDirty(mutableSource) { - workInProgressSources.push(mutableSource); -} -function resetWorkInProgressVersions() { - for (var i = 0; i < workInProgressSources.length; i++) { - var mutableSource = workInProgressSources[i]; - - { - mutableSource._workInProgressVersionPrimary = null; - } + { + InvalidNestedHooksDispatcherOnUpdateInDEV.use = function (usable) { + warnInvalidHookAccess(); + return use(usable); + }; } - workInProgressSources.length = 0; -} -function getWorkInProgressVersion(mutableSource) { { - return mutableSource._workInProgressVersionPrimary; + InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; } -} -function setWorkInProgressVersion(mutableSource, version) { + { - mutableSource._workInProgressVersionPrimary = version; + InvalidNestedHooksDispatcherOnUpdateInDEV.useEffectEvent = + function useEffectEvent(callback) { + currentHookNameInDev = "useEffectEvent"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEvent(callback); + }; } - workInProgressSources.push(mutableSource); -} -function warnAboutMultipleRenderersDEV(mutableSource) { - { - { - if (mutableSource._currentPrimaryRenderer == null) { - mutableSource._currentPrimaryRenderer = rendererSigil$1; - } else if (mutableSource._currentPrimaryRenderer !== rendererSigil$1) { - error( - "Detected multiple renderers concurrently rendering the " + - "same mutable source. This is currently unsupported." - ); + InvalidNestedHooksDispatcherOnRerenderInDEV = { + readContext: function (context) { + warnInvalidContextAccess(); + return readContext(context); + }, + useCallback: function (callback, deps) { + currentHookNameInDev = "useCallback"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateCallback(callback, deps); + }, + useContext: function (context) { + currentHookNameInDev = "useContext"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return readContext(context); + }, + useEffect: function (create, deps) { + currentHookNameInDev = "useEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEffect(create, deps); + }, + useImperativeHandle: function (ref, create, deps) { + currentHookNameInDev = "useImperativeHandle"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateImperativeHandle(ref, create, deps); + }, + useInsertionEffect: function (create, deps) { + currentHookNameInDev = "useInsertionEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateInsertionEffect(create, deps); + }, + useLayoutEffect: function (create, deps) { + currentHookNameInDev = "useLayoutEffect"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateLayoutEffect(create, deps); + }, + useMemo: function (create, deps) { + currentHookNameInDev = "useMemo"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; + + try { + return updateMemo(create, deps); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useReducer: function (reducer, initialArg, init) { + currentHookNameInDev = "useReducer"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; + + try { + return rerenderReducer(reducer, initialArg, init); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; + } + }, + useRef: function (initialValue) { + currentHookNameInDev = "useRef"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateRef(); + }, + useState: function (initialState) { + currentHookNameInDev = "useState"; + warnInvalidHookAccess(); + updateHookTypesDev(); + var prevDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = + InvalidNestedHooksDispatcherOnUpdateInDEV; + + try { + return rerenderState(initialState); + } finally { + ReactCurrentDispatcher$1.current = prevDispatcher; } + }, + useDebugValue: function (value, formatterFn) { + currentHookNameInDev = "useDebugValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateDebugValue(); + }, + useDeferredValue: function (value) { + currentHookNameInDev = "useDeferredValue"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderDeferredValue(value); + }, + useTransition: function () { + currentHookNameInDev = "useTransition"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return rerenderTransition(); + }, + useMutableSource: function (source, getSnapshot, subscribe) { + currentHookNameInDev = "useMutableSource"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateMutableSource(source, getSnapshot, subscribe); + }, + useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { + currentHookNameInDev = "useSyncExternalStore"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateSyncExternalStore(subscribe, getSnapshot); + }, + useId: function () { + currentHookNameInDev = "useId"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateId(); } - } -} // Eager reads the version of a mutable source and stores it on the root. -// This ensures that the version used for server rendering matches the one -// that is eventually read during hydration. -// If they don't match there's a potential tear and a full deopt render is required. + }; -function registerMutableSourceForHydration(root, mutableSource) { - var getVersion = mutableSource._getVersion; - var version = getVersion(mutableSource._source); // TODO Clear this data once all pending hydration work is finished. - // Retaining it forever may interfere with GC. + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = + function useCacheRefresh() { + currentHookNameInDev = "useCacheRefresh"; + updateHookTypesDev(); + return updateRefresh(); + }; + } - if (root.mutableSourceEagerHydrationData == null) { - root.mutableSourceEagerHydrationData = [mutableSource, version]; - } else { - root.mutableSourceEagerHydrationData.push(mutableSource, version); + { + InvalidNestedHooksDispatcherOnRerenderInDEV.use = function (usable) { + warnInvalidHookAccess(); + return use(usable); + }; } -} -var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher, - ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig; -var didWarnAboutMismatchedHooksForComponent; -var didWarnUncachedGetSnapshot; -var didWarnAboutUseWrappedInTryCatch; + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function (size) { + warnInvalidHookAccess(); + return useMemoCache(size); + }; + } -{ - didWarnAboutMismatchedHooksForComponent = new Set(); - didWarnAboutUseWrappedInTryCatch = new Set(); -} // These are set right before calling the component. + { + InvalidNestedHooksDispatcherOnRerenderInDEV.useEffectEvent = + function useEffectEvent(callback) { + currentHookNameInDev = "useEffectEvent"; + warnInvalidHookAccess(); + updateHookTypesDev(); + return updateEvent(callback); + }; + } +} -var renderLanes$1 = NoLanes; // The work-in-progress fiber. I've named it differently to distinguish it from -// the work-in-progress hook. +var now = Scheduler.unstable_now; +var commitTime = 0; +var layoutEffectStartTime = -1; +var profilerStartTime = -1; +var passiveEffectStartTime = -1; +/** + * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect). + * + * The overall sequence is: + * 1. render + * 2. commit (and call `onRender`, `onCommit`) + * 3. check for nested updates + * 4. flush passive effects (and call `onPostCommit`) + * + * Nested updates are identified in step 3 above, + * but step 4 still applies to the work that was just committed. + * We use two flags to track nested updates then: + * one tracks whether the upcoming update is a nested update, + * and the other tracks whether the current update was a nested update. + * The first value gets synced to the second at the start of the render phase. + */ -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 currentUpdateIsNested = false; +var nestedUpdateScheduled = false; -var currentHook = null; -var workInProgressHook = null; // Whether an update was scheduled at any point during the render phase. This -// does not get reset if we do another render pass; only when we're completely -// finished evaluating this component. This is an optimization so we know -// whether we need to clear render phase updates after a throw. +function isCurrentUpdateNested() { + return currentUpdateIsNested; +} -var didScheduleRenderPhaseUpdate = false; // Where an update was scheduled only during the current render pass. This -// gets reset after each attempt. -// TODO: Maybe there's some way to consolidate this with -// `didScheduleRenderPhaseUpdate`. Or with `numberOfReRenders`. +function markNestedUpdateScheduled() { + { + nestedUpdateScheduled = true; + } +} -var didScheduleRenderPhaseUpdateDuringThisPass = false; -var shouldDoubleInvokeUserFnsInHooksDEV = false; // Counts the number of useId hooks in this component. +function resetNestedUpdateFlag() { + { + currentUpdateIsNested = false; + nestedUpdateScheduled = false; + } +} -var localIdCounter = 0; // Counts number of `use`-d thenables +function syncNestedUpdateFlag() { + { + currentUpdateIsNested = nestedUpdateScheduled; + nestedUpdateScheduled = false; + } +} -var thenableIndexCounter = 0; -var thenableState = null; // Used for ids that are generated completely client-side (i.e. not during -// hydration). This counter is global, so client ids are not stable across -// render attempts. +function getCommitTime() { + return commitTime; +} -var globalClientIdCounter = 0; -var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook +function recordCommitTime() { + commitTime = now(); +} -var currentHookNameInDev = null; // In DEV, this list ensures that hooks are called in the same order between renders. -// The list stores the order of hooks used during the initial render (mount). -// Subsequent renders (updates) reference this list. +function startProfilerTimer(fiber) { + profilerStartTime = now(); -var hookTypesDev = null; -var hookTypesUpdateIndexDev = -1; // In DEV, this tracks whether currently rendering component needs to ignore -// the dependencies for Hooks that need them (e.g. useEffect or useMemo). -// When true, such Hooks will always be "remounted". Only used during hot reload. + if (fiber.actualStartTime < 0) { + fiber.actualStartTime = now(); + } +} -var ignorePreviousDependencies = false; +function stopProfilerTimerIfRunning(fiber) { + profilerStartTime = -1; +} -function mountHookTypesDev() { - { - var hookName = currentHookNameInDev; +function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { + if (profilerStartTime >= 0) { + var elapsedTime = now() - profilerStartTime; + fiber.actualDuration += elapsedTime; - if (hookTypesDev === null) { - hookTypesDev = [hookName]; - } else { - hookTypesDev.push(hookName); + if (overrideBaseTime) { + fiber.selfBaseDuration = elapsedTime; } + + profilerStartTime = -1; } } -function updateHookTypesDev() { - { - var hookName = currentHookNameInDev; +function recordLayoutEffectDuration(fiber) { + if (layoutEffectStartTime >= 0) { + var elapsedTime = now() - layoutEffectStartTime; + layoutEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) - if (hookTypesDev !== null) { - hookTypesUpdateIndexDev++; + var parentFiber = fiber.return; - if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) { - warnOnHookMismatchInDev(hookName); + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += elapsedTime; + return; + + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += elapsedTime; + return; } - } - } -} -function checkDepsAreArrayDev(deps) { - { - if (deps !== undefined && deps !== null && !isArray(deps)) { - // Verify deps, but only on mount to avoid extra checks. - // It's unlikely their type would change as usually you define them inline. - error( - "%s received a final argument that is not an array (instead, received `%s`). When " + - "specified, the final argument must be an array.", - currentHookNameInDev, - typeof deps - ); + parentFiber = parentFiber.return; } } } -function warnOnHookMismatchInDev(currentHookName) { - { - var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1); - - if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) { - didWarnAboutMismatchedHooksForComponent.add(componentName); +function recordPassiveEffectDuration(fiber) { + if (passiveEffectStartTime >= 0) { + var elapsedTime = now() - passiveEffectStartTime; + passiveEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor + // Or the root (for the DevTools Profiler to read) - if (hookTypesDev !== null) { - var table = ""; - var secondColumnStart = 30; + var parentFiber = fiber.return; - for (var i = 0; i <= hookTypesUpdateIndexDev; i++) { - var oldHookName = hookTypesDev[i]; - var newHookName = - i === hookTypesUpdateIndexDev ? currentHookName : oldHookName; - var row = i + 1 + ". " + oldHookName; // Extra space so second column lines up - // lol @ IE not supporting String#repeat + while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; - while (row.length < secondColumnStart) { - row += " "; + if (root !== null) { + root.passiveEffectDuration += elapsedTime; } - row += newHookName + "\n"; - table += row; - } + return; - error( - "React has detected a change in the order of Hooks called by %s. " + - "This will lead to bugs and errors if not fixed. " + - "For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks\n\n" + - " Previous render Next render\n" + - " ------------------------------------------------------\n" + - "%s" + - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - componentName, - table - ); + case Profiler: + var parentStateNode = parentFiber.stateNode; + + if (parentStateNode !== null) { + // Detached fibers have their state node cleared out. + // In this case, the return pointer is also cleared out, + // so we won't be able to report the time spent in this Profiler's subtree. + parentStateNode.passiveEffectDuration += elapsedTime; + } + + return; } + + parentFiber = parentFiber.return; } } } -function throwInvalidHookError() { - throw new Error( - "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for" + - " one of the following reasons:\n" + - "1. You might have mismatching versions of React and the renderer (such as React DOM)\n" + - "2. You might be breaking the Rules of Hooks\n" + - "3. You might have more than one copy of React in the same app\n" + - "See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem." - ); +function startLayoutEffectTimer() { + layoutEffectStartTime = now(); } -function areHookInputsEqual(nextDeps, prevDeps) { - { - if (ignorePreviousDependencies) { - // Only true when this component is being hot reloaded. - return false; - } - } +function startPassiveEffectTimer() { + passiveEffectStartTime = now(); +} - if (prevDeps === null) { - { - error( - "%s received a final argument during this render, but not during " + - "the previous render. Even though the final argument is optional, " + - "its type cannot change between renders.", - currentHookNameInDev - ); - } +function transferActualDuration(fiber) { + // Transfer time spent rendering these children so we don't lose it + // after we rerender. This is used as a helper in special cases + // where we should count the work of multiple passes. + var child = fiber.child; - return false; + while (child) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + fiber.actualDuration += child.actualDuration; + child = child.sibling; } +} - { - // Don't bother comparing lengths in prod because these arrays should be - // passed inline. - if (nextDeps.length !== prevDeps.length) { - error( - "The final argument passed to %s changed size between renders. The " + - "order and size of this array must remain constant.\n\n" + - "Previous: %s\n" + - "Incoming: %s", - currentHookNameInDev, - "[" + prevDeps.join(", ") + "]", - "[" + nextDeps.join(", ") + "]" - ); - } - } // $FlowFixMe[incompatible-use] found when upgrading Flow +function resolveDefaultProps(Component, baseProps) { + if (Component && Component.defaultProps) { + // Resolve default props. Taken from ReactElement + var props = assign({}, baseProps); + var defaultProps = Component.defaultProps; - for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (objectIs(nextDeps[i], prevDeps[i])) { - continue; + for (var propName in defaultProps) { + if (props[propName] === undefined) { + props[propName] = defaultProps[propName]; + } } - return false; + return props; } - return true; + return baseProps; } -function renderWithHooks( - current, - workInProgress, - Component, - props, - secondArg, - nextRenderLanes -) { - renderLanes$1 = nextRenderLanes; - currentlyRenderingFiber$1 = workInProgress; +var fakeInternalInstance = {}; +var didWarnAboutStateAssignmentForComponent; +var didWarnAboutUninitializedState; +var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; +var didWarnAboutLegacyLifecyclesAndDerivedState; +var didWarnAboutUndefinedDerivedState; +var didWarnAboutDirectlyAssigningPropsToState; +var didWarnAboutContextTypeAndContextTypes; +var didWarnAboutInvalidateContextType; +var didWarnOnInvalidCallback; + +{ + didWarnAboutStateAssignmentForComponent = new Set(); + didWarnAboutUninitializedState = new Set(); + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); + didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); + didWarnAboutDirectlyAssigningPropsToState = new Set(); + didWarnAboutUndefinedDerivedState = new Set(); + didWarnAboutContextTypeAndContextTypes = new Set(); + didWarnAboutInvalidateContextType = new Set(); + didWarnOnInvalidCallback = new Set(); // This is so gross but it's at least non-critical and can be removed if + // it causes problems. This is meant to give a nicer error message for + // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, + // ...)) which otherwise throws a "_processChildContext is not a function" + // exception. + + Object.defineProperty(fakeInternalInstance, "_processChildContext", { + enumerable: false, + value: function () { + throw new Error( + "_processChildContext is not available in React 16+. This likely " + + "means you have multiple copies of React and are attempting to nest " + + "a React 15 tree inside a React 16 tree using " + + "unstable_renderSubtreeIntoContainer, which isn't supported. Try " + + "to make sure you have only one copy of React (and ideally, switch " + + "to ReactDOM.createPortal)." + ); + } + }); + Object.freeze(fakeInternalInstance); +} +function warnOnInvalidCallback$1(callback, callerName) { { - hookTypesDev = current !== null ? current._debugHookTypes : null; - hookTypesUpdateIndexDev = -1; // Used for hot reloading: + if (callback === null || typeof callback === "function") { + return; + } - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - } + var key = callerName + "_" + callback; - workInProgress.memoizedState = null; - workInProgress.updateQueue = null; - workInProgress.lanes = NoLanes; // The following should have already been reset - // currentHook = null; - // workInProgressHook = null; - // didScheduleRenderPhaseUpdate = false; - // localIdCounter = 0; - // thenableIndexCounter = 0; - // thenableState = null; - // TODO Warn if no hooks are used at all during mount, then some are used during update. - // Currently we will identify the update render as a mount because memoizedState === null. - // This is tricky because it's valid for certain types of components (e.g. React.lazy) - // Using memoizedState to differentiate between mount/update only works if at least one stateful hook is used. - // Non-stateful hooks (e.g. context) don't get added to memoizedState, - // so memoizedState would be null during updates and mounts. + if (!didWarnOnInvalidCallback.has(key)) { + didWarnOnInvalidCallback.add(key); - { - if (current !== null && current.memoizedState !== null) { - ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV; - } else if (hookTypesDev !== null) { - // This dispatcher handles an edge case where a component is updating, - // but no stateful hooks have been used. - // We want to match the production code behavior (which will use HooksDispatcherOnMount), - // but with the extra DEV validation to ensure hooks ordering hasn't changed. - // This dispatcher does that. - ReactCurrentDispatcher$1.current = - HooksDispatcherOnMountWithHookTypesInDEV; - } else { - ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; + error( + "%s(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callerName, + callback + ); } - } // In Strict Mode, during development, user functions are double invoked to - // help detect side effects. The logic for how this is implemented for in - // hook components is a bit complex so let's break it down. - // - // We will invoke the entire component function twice. However, during the - // second invocation of the component, the hook state from the first - // invocation will be reused. That means things like `useMemo` functions won't - // run again, because the deps will match and the memoized result will - // be reused. - // - // We want memoized functions to run twice, too, so account for this, user - // functions are double invoked during the *first* invocation of the component - // function, and are *not* double invoked during the second incovation: - // - // - First execution of component function: user functions are double invoked - // - Second execution of component function (in Strict Mode, during - // development): user functions are not double invoked. - // - // This is intentional for a few reasons; most importantly, it's because of - // how `use` works when something suspends: it reuses the promise that was - // passed during the first attempt. This is itself a form of memoization. - // We need to be able to memoize the reactive inputs to the `use` call using - // a hook (i.e. `useMemo`), which means, the reactive inputs to `use` must - // come from the same component invocation as the output. - // - // There are plenty of tests to ensure this behavior is correct. - - var shouldDoubleRenderDEV = - (workInProgress.mode & StrictLegacyMode) !== NoMode; - shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV; - var children = Component(props, secondArg); - shouldDoubleInvokeUserFnsInHooksDEV = false; // Check if there was a render phase update - - if (didScheduleRenderPhaseUpdateDuringThisPass) { - // Keep rendering until the component stabilizes (there are no more render - // phase updates). - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); } +} - if (shouldDoubleRenderDEV) { - // In development, components are invoked twice to help detect side effects. - setIsStrictModeForDevtools(true); +function warnOnUndefinedDerivedState(type, partialState) { + { + if (partialState === undefined) { + var componentName = getComponentNameFromType(type) || "Component"; - try { - children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - } finally { - setIsStrictModeForDevtools(false); + if (!didWarnAboutUndefinedDerivedState.has(componentName)) { + didWarnAboutUndefinedDerivedState.add(componentName); + + error( + "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + + "You have returned undefined.", + componentName + ); + } } } - - finishRenderingHooks(current, workInProgress); - return children; } -function finishRenderingHooks(current, workInProgress) { - // 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-entrance. - ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; - - { - workInProgress._debugHookTypes = hookTypesDev; - } // This check uses currentHook so that it works the same in DEV and prod bundles. - // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles. - - var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; - renderLanes$1 = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; +function applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + nextProps +) { + var prevState = workInProgress.memoizedState; + var partialState = getDerivedStateFromProps(nextProps, prevState); { - currentHookNameInDev = null; - hookTypesDev = null; - hookTypesUpdateIndexDev = -1; // Confirm that a static flag was not added or removed since the last - // render. If this fires, it suggests that we incorrectly reset the static - // flags in some other part of the codebase. This has happened before, for - // example, in the SuspenseList implementation. + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if ( - current !== null && - (current.flags & StaticMask) !== (workInProgress.flags & StaticMask) && // Disable this warning in legacy mode, because legacy Suspense is weird - // and creates false positives. To make this work in legacy mode, we'd - // need to mark fibers that commit in an incomplete state, somehow. For - // now I'll disable the warning that most of the bugs that would trigger - // it are either exclusive to concurrent mode or exist in both. - (current.mode & ConcurrentMode) !== NoMode - ) { - error( - "Internal React error: Expected static flag was missing. Please " + - "notify the React team." - ); + try { + // Invoke the function an extra time to help detect side-effects. + partialState = getDerivedStateFromProps(nextProps, prevState); + } finally { + setIsStrictModeForDevtools(false); + } } - } - didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook - // localIdCounter = 0; + warnOnUndefinedDerivedState(ctor, partialState); + } // Merge the partial state and the previous state. - thenableIndexCounter = 0; - thenableState = null; + 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. - if (didRenderTooFewHooks) { - throw new Error( - "Rendered fewer hooks than expected. This may be caused by an accidental " + - "early return statement." - ); + if (workInProgress.lanes === NoLanes) { + // Queue is always non-null for classes + var updateQueue = workInProgress.updateQueue; + updateQueue.baseState = memoizedState; } +} - if (enableLazyContextPropagation) { - if (current !== null) { - if (!checkIfWorkInProgressReceivedUpdate()) { - // If there were no changes to props or state, we need to check if there - // was a context change. We didn't already do this because there's no - // 1:1 correspondence between dependencies and hooks. Although, because - // there almost always is in the common case (`readContext` is an - // internal API), we could compare in there. OTOH, we only hit this case - // if everything else bails out, so on the whole it might be better to - // keep the comparison out of the common path. - var currentDependencies = current.dependencies; +var classComponentUpdater = { + isMounted: isMounted, + // $FlowFixMe[missing-local-annot] + enqueueSetState: function (inst, payload, callback) { + var fiber = get(inst); + var lane = requestUpdateLane(fiber); + var update = createUpdate(lane); + update.payload = payload; - if ( - currentDependencies !== null && - checkIfContextChanged(currentDependencies) - ) { - markWorkInProgressReceivedUpdate(); - } + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback$1(callback, "setState"); } + + update.callback = callback; } - } - { - if (checkIfUseWrappedInTryCatch()) { - var componentName = - getComponentNameFromFiber(workInProgress) || "Unknown"; + var root = enqueueUpdate(fiber, update, lane); - if (!didWarnAboutUseWrappedInTryCatch.has(componentName)) { - didWarnAboutUseWrappedInTryCatch.add(componentName); + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitions(root, fiber, lane); + } - error( - "`use` was called from inside a try/catch block. This is not allowed " + - "and can lead to unexpected behavior. To handle errors triggered " + - "by `use`, wrap your component in a error boundary." - ); + { + if (enableDebugTracing) { + if (fiber.mode & DebugTracingMode) { + var name = getComponentNameFromFiber(fiber) || "Unknown"; + logStateUpdateScheduled(name, lane, payload); + } } } - } -} -function replaySuspendedComponentWithHooks( - current, - workInProgress, - Component, - props, - secondArg -) { - // This function is used to replay a component that previously suspended, - // after its data resolves. - // - // It's a simplified version of renderWithHooks, but it doesn't need to do - // most of the set up work because they weren't reset when we suspended; they - // only get reset when the component either completes (finishRenderingHooks) - // or unwinds (resetHooksOnUnwind). - { - hookTypesUpdateIndexDev = -1; // Used for hot reloading: + if (enableSchedulingProfiler) { + markStateUpdateScheduled(fiber, lane); + } + }, + enqueueReplaceState: function (inst, payload, callback) { + var fiber = get(inst); + var lane = requestUpdateLane(fiber); + var update = createUpdate(lane); + update.tag = ReplaceState; + update.payload = payload; - ignorePreviousDependencies = - current !== null && current.type !== workInProgress.type; - } + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback$1(callback, "replaceState"); + } - var children = renderWithHooksAgain( - workInProgress, - Component, - props, - secondArg - ); - finishRenderingHooks(current, workInProgress); - return children; -} + update.callback = callback; + } -function renderWithHooksAgain(workInProgress, Component, props, secondArg) { - // This is used to perform another render pass. It's used when setState is - // called during render, and for double invoking components in Strict Mode - // during development. - // - // The state from the previous pass is reused whenever possible. So, state - // updates that were already processed are not processed again, and memoized - // functions (`useMemo`) are not invoked again. - // - // Keep rendering in a loop for as long as render phase updates continue to - // be scheduled. Use a counter to prevent infinite loops. - var numberOfReRenders = 0; - var children; + var root = enqueueUpdate(fiber, update, lane); - do { - if (didScheduleRenderPhaseUpdateDuringThisPass) { - // It's possible that a use() value depended on a state that was updated in - // this rerender, so we need to watch for different thenables this time. - thenableState = null; + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitions(root, fiber, lane); } - thenableIndexCounter = 0; - didScheduleRenderPhaseUpdateDuringThisPass = false; + { + if (enableDebugTracing) { + if (fiber.mode & DebugTracingMode) { + var name = getComponentNameFromFiber(fiber) || "Unknown"; + logStateUpdateScheduled(name, lane, payload); + } + } + } - if (numberOfReRenders >= RE_RENDER_LIMIT) { - throw new Error( - "Too many re-renders. React limits the number of renders to prevent " + - "an infinite loop." - ); + if (enableSchedulingProfiler) { + markStateUpdateScheduled(fiber, lane); } + }, + // $FlowFixMe[missing-local-annot] + enqueueForceUpdate: function (inst, callback) { + var fiber = get(inst); + var lane = requestUpdateLane(fiber); + var update = createUpdate(lane); + update.tag = ForceUpdate; - numberOfReRenders += 1; + if (callback !== undefined && callback !== null) { + { + warnOnInvalidCallback$1(callback, "forceUpdate"); + } - { - // Even when hot reloading, allow dependencies to stabilize - // after first render to prevent infinite render phase updates. - ignorePreviousDependencies = false; - } // Start over from the beginning of the list + update.callback = callback; + } - currentHook = null; - workInProgressHook = null; - workInProgress.updateQueue = null; + var root = enqueueUpdate(fiber, update, lane); - { - // Also validate hook order for cascading updates. - hookTypesUpdateIndexDev = -1; + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + entangleTransitions(root, fiber, lane); } - ReactCurrentDispatcher$1.current = HooksDispatcherOnRerenderInDEV; - children = Component(props, secondArg); - } while (didScheduleRenderPhaseUpdateDuringThisPass); + { + if (enableDebugTracing) { + if (fiber.mode & DebugTracingMode) { + var name = getComponentNameFromFiber(fiber) || "Unknown"; + logForceUpdateScheduled(name, lane); + } + } + } - return children; -} + if (enableSchedulingProfiler) { + markForceUpdateScheduled(fiber, lane); + } + } +}; -function checkDidRenderIdHook() { - // This should be called immediately after every renderWithHooks call. - // Conceptually, it's part of the return value of renderWithHooks; it's only a - // separate function to avoid using an array tuple. - var didRenderIdHook = localIdCounter !== 0; - localIdCounter = 0; - return didRenderIdHook; -} -function bailoutHooks(current, workInProgress, lanes) { - workInProgress.updateQueue = current.updateQueue; // TODO: Don't need to reset the flags here, because they're reset in the - // complete phase (bubbleProperties). +function checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext +) { + var instance = workInProgress.stateNode; - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - workInProgress.flags &= ~( - MountPassiveDev | - MountLayoutDev | - Passive$1 | - Update + if (typeof instance.shouldComponentUpdate === "function") { + var shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext ); - } else { - workInProgress.flags &= ~(Passive$1 | Update); - } - - current.lanes = removeLanes(current.lanes, lanes); -} -function resetHooksAfterThrow() { - // This is called immediaetly after a throw. It shouldn't reset the entire - // module state, because the work loop might decide to replay the component - // again without rewinding. - // - // It should only reset things like the current dispatcher, to prevent hooks - // from being called outside of a component. - // 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-entrance. - ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; -} -function resetHooksOnUnwind() { - if (didScheduleRenderPhaseUpdate) { - // There were render phase updates. These are only valid for this render - // phase, which we are now aborting. Remove the updates from the queues so - // they do not persist to the next render. Do not remove updates from hooks - // that weren't processed. - // - // Only reset the updates from the queue if it has a clone. If it does - // not have a clone, that means it wasn't processed, and the updates were - // scheduled before we entered the render phase. - var hook = currentlyRenderingFiber$1.memoizedState; - while (hook !== null) { - var queue = hook.queue; + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if (queue !== null) { - queue.pending = null; + try { + // Invoke the function an extra time to help detect side-effects. + shouldUpdate = instance.shouldComponentUpdate( + newProps, + newState, + nextContext + ); + } finally { + setIsStrictModeForDevtools(false); + } } - hook = hook.next; + if (shouldUpdate === undefined) { + error( + "%s.shouldComponentUpdate(): Returned undefined instead of a " + + "boolean value. Make sure to return true or false.", + getComponentNameFromType(ctor) || "Component" + ); + } } - didScheduleRenderPhaseUpdate = false; + return shouldUpdate; } - renderLanes$1 = NoLanes; - currentlyRenderingFiber$1 = null; - currentHook = null; - workInProgressHook = null; - - { - hookTypesDev = null; - hookTypesUpdateIndexDev = -1; - currentHookNameInDev = null; + if (ctor.prototype && ctor.prototype.isPureReactComponent) { + return ( + !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) + ); } - didScheduleRenderPhaseUpdateDuringThisPass = false; - localIdCounter = 0; - thenableIndexCounter = 0; - thenableState = null; + return true; } -function mountWorkInProgressHook() { - var hook = { - memoizedState: null, - baseState: null, - baseQueue: null, - queue: null, - next: null - }; +function checkClassInstance(workInProgress, ctor, newProps) { + var instance = workInProgress.stateNode; - if (workInProgressHook === null) { - // This is the first hook in the list - currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook; - } else { - // Append to the end of the list - workInProgressHook = workInProgressHook.next = hook; - } + { + var name = getComponentNameFromType(ctor) || "Component"; + var renderPresent = instance.render; - return workInProgressHook; -} + if (!renderPresent) { + if (ctor.prototype && typeof ctor.prototype.render === "function") { + error( + "%s(...): No `render` method found on the returned component " + + "instance: did you accidentally return an object from the constructor?", + name + ); + } else { + error( + "%s(...): No `render` method found on the returned component " + + "instance: you may have forgotten to define `render`.", + name + ); + } + } -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. - var nextCurrentHook; - - if (currentHook === null) { - var current = currentlyRenderingFiber$1.alternate; - - if (current !== null) { - nextCurrentHook = current.memoizedState; - } else { - nextCurrentHook = null; + if ( + instance.getInitialState && + !instance.getInitialState.isReactClassApproved && + !instance.state + ) { + error( + "getInitialState was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Did you mean to define a state property instead?", + name + ); } - } else { - nextCurrentHook = currentHook.next; - } - - var nextWorkInProgressHook; - - if (workInProgressHook === null) { - nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState; - } else { - nextWorkInProgressHook = workInProgressHook.next; - } - - if (nextWorkInProgressHook !== null) { - // There's already a work-in-progress. Reuse it. - workInProgressHook = nextWorkInProgressHook; - nextWorkInProgressHook = workInProgressHook.next; - currentHook = nextCurrentHook; - } else { - // Clone from the current hook. - if (nextCurrentHook === null) { - var currentFiber = currentlyRenderingFiber$1.alternate; - if (currentFiber === null) { - // This is the initial render. This branch is reached when the component - // suspends, resumes, then renders an additional hook. - // Should never be reached because we should switch to the mount dispatcher first. - throw new Error( - "Update hook called on initial render. This is likely a bug in React. Please file an issue." - ); - } else { - // This is an update. We should always have a current hook. - throw new Error("Rendered more hooks than during the previous render."); - } + if ( + instance.getDefaultProps && + !instance.getDefaultProps.isReactClassApproved + ) { + error( + "getDefaultProps was defined on %s, a plain JavaScript class. " + + "This is only supported for classes created using React.createClass. " + + "Use a static property to define defaultProps instead.", + name + ); } - currentHook = nextCurrentHook; - var newHook = { - memoizedState: currentHook.memoizedState, - baseState: currentHook.baseState, - baseQueue: currentHook.baseQueue, - queue: currentHook.queue, - next: null - }; - - if (workInProgressHook === null) { - // This is the first hook in the list. - currentlyRenderingFiber$1.memoizedState = workInProgressHook = newHook; - } else { - // Append to the end of the list. - workInProgressHook = workInProgressHook.next = newHook; + if (instance.propTypes) { + error( + "propTypes was defined as an instance property on %s. Use a static " + + "property to define propTypes instead.", + name + ); } - } - - return workInProgressHook; -} // NOTE: defining two versions of this function to avoid size impact when this feature is disabled. -// Previously this function was inlined, the additional `memoCache` property makes it not inlined. - -var createFunctionComponentUpdateQueue; - -{ - createFunctionComponentUpdateQueue = function () { - return { - lastEffect: null, - events: null, - stores: null, - memoCache: null - }; - }; -} -function use(usable) { - if (usable !== null && typeof usable === "object") { - // $FlowFixMe[method-unbinding] - if (typeof usable.then === "function") { - // This is a thenable. - var thenable = usable; // Track the position of the thenable within this fiber. - - var index = thenableIndexCounter; - thenableIndexCounter += 1; + if (instance.contextType) { + error( + "contextType was defined as an instance property on %s. Use a static " + + "property to define contextType instead.", + name + ); + } - if (thenableState === null) { - thenableState = createThenableState(); + { + if (instance.contextTypes) { + error( + "contextTypes was defined as an instance property on %s. Use a static " + + "property to define contextTypes instead.", + name + ); } - var result = trackUsedThenable(thenableState, thenable, index); - if ( - currentlyRenderingFiber$1.alternate === null && - (workInProgressHook === null - ? currentlyRenderingFiber$1.memoizedState === null - : workInProgressHook.next === null) + ctor.contextType && + ctor.contextTypes && + !didWarnAboutContextTypeAndContextTypes.has(ctor) ) { - // Initial render, and either this is the first time the component is - // called, or there were no Hooks called after this use() the previous - // time (perhaps because it threw). Subsequent Hook calls should use the - // mount dispatcher. - { - ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV; - } + didWarnAboutContextTypeAndContextTypes.add(ctor); + + error( + "%s declares both contextTypes and contextType static properties. " + + "The legacy contextTypes property will be ignored.", + name + ); } + } - return result; - } else if ( - usable.$$typeof === REACT_CONTEXT_TYPE || - usable.$$typeof === REACT_SERVER_CONTEXT_TYPE + if (typeof instance.componentShouldUpdate === "function") { + error( + "%s has a method called " + + "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + + "The name is phrased as a question because the function is " + + "expected to return a value.", + name + ); + } + + if ( + ctor.prototype && + ctor.prototype.isPureReactComponent && + typeof instance.shouldComponentUpdate !== "undefined" ) { - var context = usable; - return readContext(context); + error( + "%s has a method called shouldComponentUpdate(). " + + "shouldComponentUpdate should not be used when extending React.PureComponent. " + + "Please extend React.Component if shouldComponentUpdate is used.", + getComponentNameFromType(ctor) || "A pure component" + ); } - } // eslint-disable-next-line react-internal/safe-string-coercion - throw new Error("An unsupported type was passed to use(): " + String(usable)); -} + if (typeof instance.componentDidUnmount === "function") { + error( + "%s has a method called " + + "componentDidUnmount(). But there is no such lifecycle method. " + + "Did you mean componentWillUnmount()?", + name + ); + } -function useMemoCache(size) { - var memoCache = null; // Fast-path, load memo cache from wip fiber if already prepared + if (typeof instance.componentDidReceiveProps === "function") { + error( + "%s has a method called " + + "componentDidReceiveProps(). But there is no such lifecycle method. " + + "If you meant to update the state in response to changing props, " + + "use componentWillReceiveProps(). If you meant to fetch data or " + + "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", + name + ); + } - var updateQueue = currentlyRenderingFiber$1.updateQueue; + if (typeof instance.componentWillRecieveProps === "function") { + error( + "%s has a method called " + + "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", + name + ); + } - if (updateQueue !== null) { - memoCache = updateQueue.memoCache; - } // Otherwise clone from the current fiber + if (typeof instance.UNSAFE_componentWillRecieveProps === "function") { + error( + "%s has a method called " + + "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", + name + ); + } - if (memoCache == null) { - var current = currentlyRenderingFiber$1.alternate; + var hasMutatedProps = instance.props !== newProps; - if (current !== null) { - var currentUpdateQueue = current.updateQueue; + if (instance.props !== undefined && hasMutatedProps) { + error( + "%s(...): When calling super() in `%s`, make sure to pass " + + "up the same props that your component's constructor was passed.", + name, + name + ); + } - if (currentUpdateQueue !== null) { - var currentMemoCache = currentUpdateQueue.memoCache; + if (instance.defaultProps) { + error( + "Setting defaultProps as an instance property on %s is not supported and will be ignored." + + " Instead, define defaultProps as a static property on %s.", + name, + name + ); + } - if (currentMemoCache != null) { - memoCache = { - data: currentMemoCache.data.map(function (array) { - return array.slice(); - }), - index: 0 - }; - } - } + if ( + typeof instance.getSnapshotBeforeUpdate === "function" && + typeof instance.componentDidUpdate !== "function" && + !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) + ) { + didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + + error( + "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + + "This component defines getSnapshotBeforeUpdate() only.", + getComponentNameFromType(ctor) + ); } - } // Finally fall back to allocating a fresh instance of the cache - if (memoCache == null) { - memoCache = { - data: [], - index: 0 - }; - } + if (typeof instance.getDerivedStateFromProps === "function") { + error( + "%s: getDerivedStateFromProps() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ); + } - if (updateQueue === null) { - updateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = updateQueue; - } + if (typeof instance.getDerivedStateFromError === "function") { + error( + "%s: getDerivedStateFromError() is defined as an instance method " + + "and will be ignored. Instead, declare it as a static method.", + name + ); + } - updateQueue.memoCache = memoCache; - var data = memoCache.data[memoCache.index]; + if (typeof ctor.getSnapshotBeforeUpdate === "function") { + error( + "%s: getSnapshotBeforeUpdate() is defined as a static method " + + "and will be ignored. Instead, declare it as an instance method.", + name + ); + } - if (data === undefined) { - data = memoCache.data[memoCache.index] = new Array(size); + var state = instance.state; - for (var i = 0; i < size; i++) { - data[i] = REACT_MEMO_CACHE_SENTINEL; + if (state && (typeof state !== "object" || isArray(state))) { + error("%s.state: must be set to an object or null", name); } - } else if (data.length !== size) { - // TODO: consider warning or throwing here - { + + if ( + typeof instance.getChildContext === "function" && + typeof ctor.childContextTypes !== "object" + ) { error( - "Expected a constant size argument for each invocation of useMemoCache. " + - "The previous cache was allocated with size %s but size %s was requested.", - data.length, - size + "%s.getChildContext(): childContextTypes must be defined in order to " + + "use getChildContext().", + name ); } } - - memoCache.index++; - return data; } -function basicStateReducer(state, action) { - // $FlowFixMe: Flow doesn't like mixed types - return typeof action === "function" ? action(state) : action; -} +function adoptClassInstance(workInProgress, instance) { + instance.updater = classComponentUpdater; + workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates -function mountReducer(reducer, initialArg, init) { - var hook = mountWorkInProgressHook(); - var initialState; + set(instance, workInProgress); - if (init !== undefined) { - initialState = init(initialArg); - } else { - initialState = initialArg; + { + instance._reactInternalInstance = fakeInternalInstance; } - - hook.memoizedState = hook.baseState = initialState; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: reducer, - lastRenderedState: initialState - }; - hook.queue = queue; - var dispatch = (queue.dispatch = dispatchReducerAction.bind( - null, - currentlyRenderingFiber$1, - queue - )); - return [hook.memoizedState, dispatch]; } -function updateReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - var queue = hook.queue; - - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); - } - - queue.lastRenderedReducer = reducer; - var current = currentHook; // The last rebase update that is NOT part of the base state. +function constructClassInstance(workInProgress, ctor, props) { + var isLegacyContextConsumer = false; + var unmaskedContext = emptyContextObject; + var context = emptyContextObject; + var contextType = ctor.contextType; - var baseQueue = current.baseQueue; // The last pending update that hasn't been processed yet. + { + if ("contextType" in ctor) { + var isValid = // Allow null for conditional declaration + contextType === null || + (contextType !== undefined && + contextType.$$typeof === REACT_CONTEXT_TYPE && + contextType._context === undefined); // Not a - var pendingQueue = queue.pending; + if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { + didWarnAboutInvalidateContextType.add(ctor); + var addendum = ""; - if (pendingQueue !== null) { - // We have new updates that haven't been processed yet. - // We'll add them to the base queue. - if (baseQueue !== null) { - // Merge the pending queue and the base queue. - var baseFirst = baseQueue.next; - var pendingFirst = pendingQueue.next; - baseQueue.next = pendingFirst; - pendingQueue.next = baseFirst; - } + if (contextType === undefined) { + addendum = + " However, it is set to undefined. " + + "This can be caused by a typo or by mixing up named and default imports. " + + "This can also happen due to a circular dependency, so " + + "try moving the createContext() call to a separate file."; + } else if (typeof contextType !== "object") { + addendum = " However, it is set to a " + typeof contextType + "."; + } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { + addendum = " Did you accidentally pass the Context.Provider instead?"; + } else if (contextType._context !== undefined) { + // + addendum = " Did you accidentally pass the Context.Consumer instead?"; + } else { + addendum = + " However, it is set to an object with keys {" + + Object.keys(contextType).join(", ") + + "}."; + } - { - if (current.baseQueue !== baseQueue) { - // Internal invariant that should never happen, but feasibly could in - // the future if we implement resuming, or some form of that. error( - "Internal error: Expected work-in-progress queue to be a clone. " + - "This is a bug in React." + "%s defines an invalid contextType. " + + "contextType should point to the Context object returned by React.createContext().%s", + getComponentNameFromType(ctor) || "Component", + addendum ); } } + } - current.baseQueue = baseQueue = pendingQueue; - queue.pending = null; + 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; } - if (baseQueue !== null) { - // We have a queue to process. - var first = baseQueue.next; - var newState = current.baseState; - var newBaseState = null; - var newBaseQueueFirst = null; - var newBaseQueueLast = null; - var update = first; + var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. - do { - // An extra OffscreenLane bit is added to updates that were made to - // a hidden tree, so that we can distinguish them from updates that were - // already there when the tree was hidden. - var updateLane = removeLanes(update.lane, OffscreenLane); - var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then - // it's not a "base" update and we should disregard the extra base lanes - // that were added to renderLanes when we entered the Offscreen tree. + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - var shouldSkipUpdate = isHiddenUpdate - ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) - : !isSubsetOfLanes(renderLanes$1, updateLane); + try { + instance = new ctor(props, context); // eslint-disable-line no-new + } finally { + setIsStrictModeForDevtools(false); + } + } + } - if (shouldSkipUpdate) { - // Priority is insufficient. Skip this update. If this is the first - // skipped update, the previous update/state is the new base - // update/state. - var clone = { - lane: updateLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; + var state = (workInProgress.memoizedState = + instance.state !== null && instance.state !== undefined + ? instance.state + : null); + adoptClassInstance(workInProgress, instance); - if (newBaseQueueLast === null) { - newBaseQueueFirst = newBaseQueueLast = clone; - newBaseState = newState; - } else { - newBaseQueueLast = newBaseQueueLast.next = clone; - } // Update the remaining priority in the queue. - // TODO: Don't need to accumulate this. Instead, we can remove - // renderLanes from the original lanes. + { + if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { + var componentName = getComponentNameFromType(ctor) || "Component"; - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - updateLane + if (!didWarnAboutUninitializedState.has(componentName)) { + didWarnAboutUninitializedState.add(componentName); + + error( + "`%s` uses `getDerivedStateFromProps` but its initial state is " + + "%s. This is not recommended. Instead, define the initial state by " + + "assigning an object to `this.state` in the constructor of `%s`. " + + "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", + componentName, + instance.state === null ? "null" : "undefined", + componentName ); - markSkippedUpdateLanes(updateLane); - } else { - // This update does have sufficient priority. - if (newBaseQueueLast !== null) { - var _clone = { - // This update is going to be committed so we never want uncommit - // it. Using NoLane works because 0 is a subset of all bitmasks, so - // this will never be skipped by the check above. - lane: NoLane, - action: update.action, - hasEagerState: update.hasEagerState, - eagerState: update.eagerState, - next: null - }; - newBaseQueueLast = newBaseQueueLast.next = _clone; - } // Process this update. + } + } // If new component APIs are defined, "unsafe" lifecycles won't be called. + // Warn about these lifecycles if they are present. + // Don't warn about react-lifecycles-compat polyfilled methods though. - var action = update.action; + if ( + typeof ctor.getDerivedStateFromProps === "function" || + typeof instance.getSnapshotBeforeUpdate === "function" + ) { + var foundWillMountName = null; + var foundWillReceivePropsName = null; + var foundWillUpdateName = null; - if (shouldDoubleInvokeUserFnsInHooksDEV) { - reducer(newState, action); - } + if ( + typeof instance.componentWillMount === "function" && + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + foundWillMountName = "componentWillMount"; + } else if (typeof instance.UNSAFE_componentWillMount === "function") { + foundWillMountName = "UNSAFE_componentWillMount"; + } - if (update.hasEagerState) { - // If this update is a state update (not a reducer) and was processed eagerly, - // we can use the eagerly computed state - newState = update.eagerState; - } else { - newState = reducer(newState, action); - } + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + foundWillReceivePropsName = "componentWillReceiveProps"; + } else if ( + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; } - update = update.next; - } while (update !== null && update !== first); + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + foundWillUpdateName = "componentWillUpdate"; + } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { + foundWillUpdateName = "UNSAFE_componentWillUpdate"; + } - if (newBaseQueueLast === null) { - newBaseState = newState; - } else { - newBaseQueueLast.next = newBaseQueueFirst; - } // Mark that the fiber performed work, but only if the new state is - // different from the current state. + if ( + foundWillMountName !== null || + foundWillReceivePropsName !== null || + foundWillUpdateName !== null + ) { + var _componentName = getComponentNameFromType(ctor) || "Component"; - if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); - } + var newApiName = + typeof ctor.getDerivedStateFromProps === "function" + ? "getDerivedStateFromProps()" + : "getSnapshotBeforeUpdate()"; - hook.memoizedState = newState; - hook.baseState = newBaseState; - hook.baseQueue = newBaseQueueLast; - queue.lastRenderedState = newState; - } + if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { + didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - if (baseQueue === null) { - // `queue.lanes` is used for entangling transitions. We can set it back to - // zero once the queue is empty. - queue.lanes = NoLanes; + error( + "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + + "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + + "The above lifecycles should be removed. Learn more about this warning here:\n" + + "https://reactjs.org/link/unsafe-component-lifecycles", + _componentName, + newApiName, + foundWillMountName !== null ? "\n " + foundWillMountName : "", + foundWillReceivePropsName !== null + ? "\n " + foundWillReceivePropsName + : "", + foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" + ); + } + } + } + } // Cache unmasked context so we can avoid recreating masked context unless necessary. + // ReactFiberContext usually updates this cache but can't for newly-created instances. + + if (isLegacyContextConsumer) { + cacheContext(workInProgress, unmaskedContext, context); } - var dispatch = queue.dispatch; - return [hook.memoizedState, dispatch]; + return instance; } -function rerenderReducer(reducer, initialArg, init) { - var hook = updateWorkInProgressHook(); - var queue = hook.queue; +function callComponentWillMount(workInProgress, instance) { + var oldState = instance.state; - if (queue === null) { - throw new Error( - "Should have a queue. This is likely a bug in React. Please file an issue." - ); + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); } - queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous - // work-in-progress hook. + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } - var dispatch = queue.dispatch; - var lastRenderPhaseUpdate = queue.pending; - var newState = hook.memoizedState; + if (oldState !== instance.state) { + { + error( + "%s.componentWillMount(): Assigning directly to this.state is " + + "deprecated (except inside a component's " + + "constructor). Use setState instead.", + getComponentNameFromFiber(workInProgress) || "Component" + ); + } - if (lastRenderPhaseUpdate !== null) { - // The queue doesn't persist past this render pass. - queue.pending = null; - var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next; - var update = firstRenderPhaseUpdate; + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + } +} - 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 !== firstRenderPhaseUpdate); // Mark that the fiber performed work, but only if the new state is - // different from the current state. +function callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext +) { + var oldState = instance.state; - if (!objectIs(newState, hook.memoizedState)) { - markWorkInProgressReceivedUpdate(); - } + if (typeof instance.componentWillReceiveProps === "function") { + instance.componentWillReceiveProps(newProps, nextContext); + } - hook.memoizedState = newState; // Don't persist the state accumulated 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 (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); + } - if (hook.baseQueue === null) { - hook.baseState = newState; + if (instance.state !== oldState) { + { + var componentName = + getComponentNameFromFiber(workInProgress) || "Component"; + + if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { + didWarnAboutStateAssignmentForComponent.add(componentName); + + error( + "%s.componentWillReceiveProps(): Assigning directly to " + + "this.state is deprecated (except inside a component's " + + "constructor). Use setState instead.", + componentName + ); + } } - queue.lastRenderedState = newState; + classComponentUpdater.enqueueReplaceState(instance, instance.state, null); } +} // Invokes the mount life-cycles on a previously never rendered instance. - return [newState, dispatch]; -} - -function readFromUnsubscribedMutableSource(root, source, getSnapshot) { +function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { { - warnAboutMultipleRenderersDEV(source); + checkClassInstance(workInProgress, ctor, newProps); } - var getVersion = source._getVersion; - var version = getVersion(source._source); // Is it safe for this component to read from this source during the current render? - - var isSafeToReadFromSource = false; // Check the version first. - // If this render has already been started with a specific version, - // we can use it alone to determine if we can safely read from the source. - - var currentRenderVersion = getWorkInProgressVersion(source); + var instance = workInProgress.stateNode; + instance.props = newProps; + instance.state = workInProgress.memoizedState; + instance.refs = {}; + initializeUpdateQueue(workInProgress); + var contextType = ctor.contextType; - if (currentRenderVersion !== null) { - // It's safe to read if the store hasn't been mutated since the last time - // we read something. - isSafeToReadFromSource = currentRenderVersion === version; + if (typeof contextType === "object" && contextType !== null) { + instance.context = readContext(contextType); } else { - // If there's no version, then this is the first time we've read from the - // source during the current render pass, so we need to do a bit more work. - // What we need to determine is if there are any hooks that already - // subscribed to the source, and if so, whether there are any pending - // mutations that haven't been synchronized yet. - // - // If there are no pending mutations, then `root.mutableReadLanes` will be - // empty, and we know we can safely read. - // - // If there *are* pending mutations, we may still be able to safely read - // if the currently rendering lanes are inclusive of the pending mutation - // lanes, since that guarantees that the value we're about to read from - // the source is consistent with the values that we read during the most - // recent mutation. - isSafeToReadFromSource = isSubsetOfLanes( - renderLanes$1, - root.mutableReadLanes - ); - - if (isSafeToReadFromSource) { - // If it's safe to read from this source during the current render, - // store the version in case other components read from it. - // A changed version number will let those components know to throw and restart the render. - setWorkInProgressVersion(source, version); - } + var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); + instance.context = getMaskedContext(workInProgress, unmaskedContext); } - if (isSafeToReadFromSource) { - var snapshot = getSnapshot(source._source); + { + if (instance.state === newProps) { + var componentName = getComponentNameFromType(ctor) || "Component"; + + if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { + didWarnAboutDirectlyAssigningPropsToState.add(componentName); - { - if (typeof snapshot === "function") { error( - "Mutable source should not return a function as the snapshot value. " + - "Functions may close over mutable values and cause tearing." + "%s: It is not recommended to assign props directly to state " + + "because updates to props won't be reflected in state. " + + "In most cases, it is better to use props directly.", + componentName ); } } - return snapshot; - } else { - // This handles the special case of a mutable source being shared between renderers. - // In that case, if the source is mutated between the first and second renderer, - // The second renderer don't know that it needs to reset the WIP version during unwind, - // (because the hook only marks sources as dirty if it's written to their WIP version). - // That would cause this tear check to throw again and eventually be visible to the user. - // We can avoid this infinite loop by explicitly marking the source as dirty. - // - // This can lead to tearing in the first renderer when it resumes, - // but there's nothing we can do about that (short of throwing here and refusing to continue the render). - markSourceAsDirty(source); // Intentioally throw an error to force React to retry synchronously. During - // the synchronous retry, it will block interleaved mutations, so we should - // get a consistent read. Therefore, the following error should never be - // visible to the user. - // We expect this error not to be thrown during the synchronous retry, - // because we blocked interleaved mutations. + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning( + workInProgress, + instance + ); + } - throw new Error( - "Cannot read from mutable source during the current render without tearing. This may be a bug in React. Please file an issue." + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( + workInProgress, + instance ); } -} -function useMutableSource(hook, source, getSnapshot, subscribe) { - var root = getWorkInProgressRoot(); + instance.state = workInProgress.memoizedState; + var getDerivedStateFromProps = ctor.getDerivedStateFromProps; - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." + 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. - var getVersion = source._getVersion; - var version = getVersion(source._source); - var dispatcher = ReactCurrentDispatcher$1.current; // eslint-disable-next-line prefer-const + 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. - var _dispatcher$useState = dispatcher.useState(function () { - return readFromUnsubscribedMutableSource(root, source, getSnapshot); - }), - currentSnapshot = _dispatcher$useState[0], - setSnapshot = _dispatcher$useState[1]; + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + instance.state = workInProgress.memoizedState; + } - var snapshot = currentSnapshot; // Grab a handle to the state hook as well. - // We use it to clear the pending update queue if we have a new source. + if (typeof instance.componentDidMount === "function") { + var fiberFlags = Update | LayoutStatic; - var stateHook = workInProgressHook; - var memoizedState = hook.memoizedState; - var refs = memoizedState.refs; - var prevGetSnapshot = refs.getSnapshot; - var prevSource = memoizedState.source; - var prevSubscribe = memoizedState.subscribe; - var fiber = currentlyRenderingFiber$1; - hook.memoizedState = { - refs: refs, - source: source, - subscribe: subscribe - }; // Sync the values needed by our subscription handler after each commit. + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; + } - dispatcher.useEffect( - function () { - refs.getSnapshot = getSnapshot; // Normally the dispatch function for a state hook never changes, - // but this hook recreates the queue in certain cases to avoid updates from stale sources. - // handleChange() below needs to reference the dispatch function without re-subscribing, - // so we use a ref to ensure that it always has the latest version. + workInProgress.flags |= fiberFlags; + } +} - refs.setSnapshot = setSnapshot; // Check for a possible change between when we last rendered now. +function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) { + var instance = workInProgress.stateNode; + var oldProps = workInProgress.memoizedProps; + instance.props = oldProps; + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = emptyContextObject; - var maybeNewVersion = getVersion(source._source); + if (typeof contextType === "object" && contextType !== null) { + nextContext = readContext(contextType); + } else { + var nextLegacyUnmaskedContext = getUnmaskedContext( + workInProgress, + ctor, + true + ); + nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); + } - if (!objectIs(version, maybeNewVersion)) { - var maybeNewSnapshot = getSnapshot(source._source); + 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 (typeof maybeNewSnapshot === "function") { - error( - "Mutable source should not return a function as the snapshot value. " + - "Functions may close over mutable values and cause tearing." - ); - } - } + if ( + !hasNewLifecycles && + (typeof instance.UNSAFE_componentWillReceiveProps === "function" || + typeof instance.componentWillReceiveProps === "function") + ) { + if (oldProps !== newProps || oldContext !== nextContext) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext + ); + } + } - if (!objectIs(snapshot, maybeNewSnapshot)) { - setSnapshot(maybeNewSnapshot); - var lane = requestUpdateLane(fiber); - markRootMutableRead(root, lane); - } // If the source mutated between render and now, - // there may be state updates already scheduled from the old source. - // Entangle the updates so that they render in the same batch. + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + newState = workInProgress.memoizedState; - markRootEntangled(root, root.mutableReadLanes); + 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") { + var fiberFlags = Update | LayoutStatic; + + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + fiberFlags |= MountLayoutDev; } - }, - [getSnapshot, source, subscribe] - ); // If we got a new source or subscribe function, re-subscribe in a passive effect. - dispatcher.useEffect( - function () { - var handleChange = function () { - var latestGetSnapshot = refs.getSnapshot; - var latestSetSnapshot = refs.setSnapshot; + workInProgress.flags |= fiberFlags; + } - try { - latestSetSnapshot(latestGetSnapshot(source._source)); // Record a pending mutable source update with the same expiration time. + return false; + } - var lane = requestUpdateLane(fiber); - markRootMutableRead(root, lane); - } catch (error) { - // A selector might throw after a source mutation. - // e.g. it might try to read from a part of the store that no longer exists. - // In this case we should still schedule an update with React. - // Worst case the selector will throw again and then an error boundary will handle it. - latestSetSnapshot(function () { - throw error; - }); - } - }; + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } - var unsubscribe = subscribe(source._source, handleChange); + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ); - { - if (typeof unsubscribe !== "function") { - error( - "Mutable source subscribe function must return an unsubscribe function." - ); - } + 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") + ) { + if (typeof instance.componentWillMount === "function") { + instance.componentWillMount(); } - return unsubscribe; - }, - [source, subscribe] - ); // If any of the inputs to useMutableSource change, reading is potentially unsafe. - // - // If either the source or the subscription have changed we can't can't trust the update queue. - // Maybe the source changed in a way that the old subscription ignored but the new one depends on. - // - // If the getSnapshot function changed, we also shouldn't rely on the update queue. - // It's possible that the underlying source was mutated between the when the last "change" event fired, - // and when the current render (with the new getSnapshot function) is processed. - // - // In both cases, we need to throw away pending updates (since they are no longer relevant) - // and treat reading from the source as we do in the mount case. + if (typeof instance.UNSAFE_componentWillMount === "function") { + instance.UNSAFE_componentWillMount(); + } + } - if ( - !objectIs(prevGetSnapshot, getSnapshot) || - !objectIs(prevSource, source) || - !objectIs(prevSubscribe, subscribe) - ) { - // Create a new queue and setState method, - // So if there are interleaved updates, they get pushed to the older queue. - // When this becomes current, the previous queue and dispatch method will be discarded, - // including any interleaving updates that occur. - var newQueue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: basicStateReducer, - lastRenderedState: snapshot - }; - newQueue.dispatch = setSnapshot = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - newQueue - ); - stateHook.queue = newQueue; - stateHook.baseQueue = null; - snapshot = readFromUnsubscribedMutableSource(root, source, getSnapshot); - stateHook.memoizedState = stateHook.baseState = snapshot; - } + if (typeof instance.componentDidMount === "function") { + var _fiberFlags = Update | LayoutStatic; - return snapshot; -} + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + _fiberFlags |= MountLayoutDev; + } -function mountMutableSource(source, getSnapshot, subscribe) { - var hook = mountWorkInProgressHook(); - hook.memoizedState = { - refs: { - getSnapshot: getSnapshot, - setSnapshot: null - }, - source: source, - subscribe: subscribe - }; - return useMutableSource(hook, source, getSnapshot, subscribe); -} + workInProgress.flags |= _fiberFlags; + } + } 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") { + var _fiberFlags2 = Update | LayoutStatic; -function updateMutableSource(source, getSnapshot, subscribe) { - var hook = updateWorkInProgressHook(); - return useMutableSource(hook, source, getSnapshot, subscribe); -} + if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { + _fiberFlags2 |= MountLayoutDev; + } -function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var fiber = currentlyRenderingFiber$1; - var hook = mountWorkInProgressHook(); - var nextSnapshot; - var isHydrating = getIsHydrating(); + workInProgress.flags |= _fiberFlags2; + } // If shouldComponentUpdate returned false, we should still update the + // memoized state to indicate that this work can be reused. - if (isHydrating) { - if (getServerSnapshot === undefined) { - throw new Error( - "Missing getServerSnapshot, which is required for " + - "server-rendered content. Will revert to client rendering." + 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, + renderLanes +) { + var instance = workInProgress.stateNode; + cloneUpdateQueue(current, workInProgress); + var unresolvedOldProps = workInProgress.memoizedProps; + var oldProps = + workInProgress.type === workInProgress.elementType + ? unresolvedOldProps + : resolveDefaultProps(workInProgress.type, unresolvedOldProps); + instance.props = oldProps; + var unresolvedNewProps = workInProgress.pendingProps; + var oldContext = instance.context; + var contextType = ctor.contextType; + var nextContext = emptyContextObject; + + 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 ( + unresolvedOldProps !== unresolvedNewProps || + oldContext !== nextContext + ) { + callComponentWillReceiveProps( + workInProgress, + instance, + newProps, + nextContext ); } + } - nextSnapshot = getServerSnapshot(); + resetHasForceUpdateBeforeProcessing(); + var oldState = workInProgress.memoizedState; + var newState = (instance.state = oldState); + processUpdateQueue(workInProgress, newProps, instance, renderLanes); + newState = workInProgress.memoizedState; - { - if (!didWarnUncachedGetSnapshot) { - if (nextSnapshot !== getServerSnapshot()) { - error( - "The result of getServerSnapshot should be cached to avoid an infinite loop" - ); + if ( + unresolvedOldProps === unresolvedNewProps && + oldState === newState && + !hasContextChanged() && + !checkHasForceUpdateAfterProcessing() && + !( + enableLazyContextPropagation && + current !== null && + current.dependencies !== null && + checkIfContextChanged(current.dependencies) + ) + ) { + // 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 ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Update; + } + } - didWarnUncachedGetSnapshot = true; - } + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Snapshot; } } - } else { - nextSnapshot = getSnapshot(); - { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); + return false; + } - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); + if (typeof getDerivedStateFromProps === "function") { + applyDerivedStateFromProps( + workInProgress, + ctor, + getDerivedStateFromProps, + newProps + ); + newState = workInProgress.memoizedState; + } - didWarnUncachedGetSnapshot = true; - } + var shouldUpdate = + checkHasForceUpdateAfterProcessing() || + checkShouldComponentUpdate( + workInProgress, + ctor, + oldProps, + newProps, + oldState, + newState, + nextContext + ) || // TODO: In some cases, we'll end up checking if context has changed twice, + // both before and after `shouldComponentUpdate` has been called. Not ideal, + // but I'm loath to refactor this function. This only happens for memoized + // components so it's not that common. + (enableLazyContextPropagation && + current !== null && + current.dependencies !== null && + checkIfContextChanged(current.dependencies)); + + 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") + ) { + if (typeof instance.componentWillUpdate === "function") { + instance.componentWillUpdate(newProps, newState, nextContext); } - } // Unless we're rendering a blocking lane, schedule a consistency check. - // Right before committing, we will walk the tree and check if any of the - // stores were mutated. - // - // We won't do this if we're hydrating server-rendered content, because if - // the content is stale, it's already visible anyway. Instead we'll patch - // it up in a passive effect. - var root = getWorkInProgressRoot(); + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + } + } - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); + if (typeof instance.componentDidUpdate === "function") { + workInProgress.flags |= Update; } - if (!includesBlockingLane(root, renderLanes$1)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + if (typeof instance.getSnapshotBeforeUpdate === "function") { + workInProgress.flags |= 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 ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Update; + } } - } // Read the current snapshot from the store on every render. This breaks the - // normal rules of React, and only works because store updates are - // always synchronous. - hook.memoizedState = nextSnapshot; - var inst = { - value: nextSnapshot, - getSnapshot: getSnapshot - }; - hook.queue = inst; // Schedule an effect to subscribe to the store. + if (typeof instance.getSnapshotBeforeUpdate === "function") { + if ( + unresolvedOldProps !== current.memoizedProps || + oldState !== current.memoizedState + ) { + workInProgress.flags |= Snapshot; + } + } // If shouldComponentUpdate returned false, we should still update the + // memoized props/state to indicate that this work can be reused. - mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [subscribe]); // Schedule an effect to update the mutable instance fields. We will update - // this whenever subscribe, getSnapshot, or value changes. Because there's no - // clean-up function, and we track the deps correctly, we can call pushEffect - // directly, without storing any additional state. For the same reason, we - // don't need to set a static flag, either. - // TODO: We can move this to the passive phase once we add a pre-commit - // consistency check. See the next comment. + workInProgress.memoizedProps = newProps; + workInProgress.memoizedState = newState; + } // Update the existing instance's state, props, and context pointers even + // if shouldComponentUpdate returns false. - fiber.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), - undefined, - null - ); - return nextSnapshot; + instance.props = newProps; + instance.state = newState; + instance.context = nextContext; + return shouldUpdate; } -function updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) { - var fiber = currentlyRenderingFiber$1; - var hook = updateWorkInProgressHook(); // Read the current snapshot from the store on every render. This breaks the - // normal rules of React, and only works because store updates are - // always synchronous. +function createCapturedValueAtFiber(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), + digest: null + }; +} +function createCapturedValue(value, digest, stack) { + return { + value: value, + source: null, + stack: stack != null ? stack : null, + digest: digest != null ? digest : null + }; +} - var nextSnapshot = getSnapshot(); +var ReactFiberErrorDialogWWW = require("ReactFiberErrorDialog"); - { - if (!didWarnUncachedGetSnapshot) { - var cachedSnapshot = getSnapshot(); +if (typeof ReactFiberErrorDialogWWW.showErrorDialog !== "function") { + throw new Error( + "Expected ReactFiberErrorDialog.showErrorDialog to be a function." + ); +} - if (!objectIs(nextSnapshot, cachedSnapshot)) { - error( - "The result of getSnapshot should be cached to avoid an infinite loop" - ); +function showErrorDialog(boundary, errorInfo) { + var capturedError = { + componentStack: errorInfo.stack !== null ? errorInfo.stack : "", + error: errorInfo.value, + errorBoundary: + boundary !== null && boundary.tag === ClassComponent + ? boundary.stateNode + : null + }; + return ReactFiberErrorDialogWWW.showErrorDialog(capturedError); +} - didWarnUncachedGetSnapshot = true; - } +function logCapturedError(boundary, errorInfo) { + try { + var logError = showErrorDialog(boundary, errorInfo); // Allow injected showErrorDialog() to prevent default console.error logging. + // This enables renderers like ReactNative to better manage redbox behavior. + + if (logError === false) { + return; } - } - var prevSnapshot = (currentHook || hook).memoizedState; - var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot); + var error = errorInfo.value; - if (snapshotChanged) { - hook.memoizedState = nextSnapshot; - markWorkInProgressReceivedUpdate(); - } + if (true) { + var source = errorInfo.source; + var stack = errorInfo.stack; + var componentStack = stack !== null ? stack : ""; // Browsers support silencing uncaught errors by calling + // `preventDefault()` in window `error` handler. + // We record this information as an expando on the error. - var inst = hook.queue; - updateEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [ - subscribe - ]); // Whenever getSnapshot or subscribe changes, we need to check in the - // commit phase if there was an interleaved mutation. In concurrent mode - // this can happen all the time, but even in synchronous mode, an earlier - // effect may have mutated the store. + if (error != null && error._suppressLogging) { + if (boundary.tag === ClassComponent) { + // The error is recoverable and was silenced. + // Ignore it and don't print the stack addendum. + // This is handy for testing error boundaries without noise. + return; + } // The error is fatal. Since the silencing might have + // been accidental, we'll surface it anyway. + // However, the browser would have silenced the original error + // so we'll print it first, and then print the stack addendum. - if ( - inst.getSnapshot !== getSnapshot || - snapshotChanged || // Check if the susbcribe function changed. We can save some memory by - // checking whether we scheduled a subscription effect above. - (workInProgressHook !== null && - workInProgressHook.memoizedState.tag & HasEffect) - ) { - fiber.flags |= Passive$1; - pushEffect( - HasEffect | Passive, - updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), - undefined, - null - ); // Unless we're rendering a blocking lane, schedule a consistency check. - // Right before committing, we will walk the tree and check if any of the - // stores were mutated. + console["error"](error); // Don't transform to our wrapper + // For a more detailed description of this block, see: + // https://github.com/facebook/react/pull/13384 + } - var root = getWorkInProgressRoot(); + var componentName = source ? getComponentNameFromFiber(source) : null; + var componentNameMessage = componentName + ? "The above error occurred in the <" + componentName + "> component:" + : "The above error occurred in one of your React components:"; + var errorBoundaryMessage; - if (root === null) { - throw new Error( - "Expected a work-in-progress root. This is a bug in React. Please file an issue." - ); - } + if (boundary.tag === HostRoot) { + errorBoundaryMessage = + "Consider adding an error boundary to your tree to customize error handling behavior.\n" + + "Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries."; + } else { + var errorBoundaryName = + getComponentNameFromFiber(boundary) || "Anonymous"; + errorBoundaryMessage = + "React will try to recreate this component tree from scratch " + + ("using the error boundary you provided, " + errorBoundaryName + "."); + } - if (!includesBlockingLane(root, renderLanes$1)) { - pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot); + var combinedMessage = + componentNameMessage + + "\n" + + componentStack + + "\n\n" + + ("" + errorBoundaryMessage); // In development, we provide our own message with just the component stack. + // We don't include the original error message and JS stack because the browser + // has already printed it. Even if the application swallows the error, it is still + // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. + + console["error"](combinedMessage); // Don't transform to our wrapper } + } 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; + }); } - - return nextSnapshot; } -function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) { - fiber.flags |= StoreConsistency; - var check = { - getSnapshot: getSnapshot, - value: renderedSnapshot - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; +function createRootErrorUpdate(fiber, errorInfo, lane) { + var update = createUpdate(lane); // Unmount the root by rendering null. - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.stores = [check]; - } else { - var stores = componentUpdateQueue.stores; + update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property + // being called "element". - if (stores === null) { - componentUpdateQueue.stores = [check]; - } else { - stores.push(check); - } - } -} + update.payload = { + element: null + }; + var error = errorInfo.value; -function updateStoreInstance(fiber, inst, nextSnapshot, getSnapshot) { - // These are updated in the passive phase - inst.value = nextSnapshot; - inst.getSnapshot = getSnapshot; // Something may have been mutated in between render and commit. This could - // have been in an event that fired before the passive effects, or it could - // have been in a layout effect. In that case, we would have used the old - // snapsho and getSnapshot values to bail out. We need to check one more time. + update.callback = function () { + onUncaughtError(error); + logCapturedError(fiber, errorInfo); + }; - if (checkIfSnapshotChanged(inst)) { - // Force a re-render. - forceStoreRerender(fiber); - } + return update; } -function subscribeToStore(fiber, inst, subscribe) { - var handleStoreChange = function () { - // The store changed. Check if the snapshot changed since the last time we - // read from the store. - if (checkIfSnapshotChanged(inst)) { - // Force a re-render. - forceStoreRerender(fiber); - } - }; // Subscribe to the store and return a clean-up function. - - return subscribe(handleStoreChange); -} - -function checkIfSnapshotChanged(inst) { - var latestGetSnapshot = inst.getSnapshot; - var prevValue = inst.value; - - try { - var nextValue = latestGetSnapshot(); - return !objectIs(prevValue, nextValue); - } catch (error) { - return true; - } -} - -function forceStoreRerender(fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } -} - -function mountState(initialState) { - var hook = mountWorkInProgressHook(); - - if (typeof initialState === "function") { - // $FlowFixMe: Flow doesn't like mixed types - initialState = initialState(); - } - - hook.memoizedState = hook.baseState = initialState; - var queue = { - pending: null, - lanes: NoLanes, - dispatch: null, - lastRenderedReducer: basicStateReducer, - lastRenderedState: initialState - }; - hook.queue = queue; - var dispatch = (queue.dispatch = dispatchSetState.bind( - null, - currentlyRenderingFiber$1, - queue - )); - return [hook.memoizedState, dispatch]; -} - -function updateState(initialState) { - return updateReducer(basicStateReducer); -} - -function rerenderState(initialState) { - return rerenderReducer(basicStateReducer); -} - -function pushEffect(tag, create, destroy, deps) { - var effect = { - tag: tag, - create: create, - destroy: destroy, - deps: deps, - // Circular - next: null - }; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; - - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - 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; - } - } +function createClassErrorUpdate(fiber, errorInfo, lane) { + var update = createUpdate(lane); + update.tag = CaptureUpdate; + var getDerivedStateFromError = fiber.type.getDerivedStateFromError; - return effect; -} + if (typeof getDerivedStateFromError === "function") { + var error$1 = errorInfo.value; -var stackContainsErrorMessage = null; + update.payload = function () { + return getDerivedStateFromError(error$1); + }; -function getCallerStackFrame() { - // eslint-disable-next-line react-internal/prod-error-codes - var stackFrames = new Error("Error message").stack.split("\n"); // Some browsers (e.g. Chrome) include the error message in the stack - // but others (e.g. Firefox) do not. + update.callback = function () { + { + markFailedErrorBoundaryForHotReloading(fiber); + } - if (stackContainsErrorMessage === null) { - stackContainsErrorMessage = stackFrames[0].includes("Error message"); + logCapturedError(fiber, errorInfo); + }; } - return stackContainsErrorMessage - ? stackFrames.slice(3, 4).join("\n") - : stackFrames.slice(2, 3).join("\n"); -} - -function mountRef(initialValue) { - var hook = mountWorkInProgressHook(); - - if (enableUseRefAccessWarning) { - { - // Support lazy initialization pattern shown in docs. - // We need to store the caller stack frame so that we don't warn on subsequent renders. - var hasBeenInitialized = initialValue != null; - var lazyInitGetterStack = null; - var didCheckForLazyInit = false; // Only warn once per component+hook. + var inst = fiber.stateNode; - var didWarnAboutRead = false; - var didWarnAboutWrite = false; - var current = initialValue; - var ref = { - get current() { - if (!hasBeenInitialized) { - didCheckForLazyInit = true; - lazyInitGetterStack = getCallerStackFrame(); - } else if (currentlyRenderingFiber$1 !== null && !didWarnAboutRead) { - if ( - lazyInitGetterStack === null || - lazyInitGetterStack !== getCallerStackFrame() - ) { - didWarnAboutRead = true; + if (inst !== null && typeof inst.componentDidCatch === "function") { + // $FlowFixMe[missing-this-annot] + update.callback = function callback() { + { + markFailedErrorBoundaryForHotReloading(fiber); + } - warn( - "%s: Unsafe read of a mutable value during render.\n\n" + - "Reading from a ref during render is only safe if:\n" + - "1. The ref value has not been updated, or\n" + - "2. The ref holds a lazily-initialized value that is only set once.\n", - getComponentNameFromFiber(currentlyRenderingFiber$1) || - "Unknown" - ); - } - } + logCapturedError(fiber, errorInfo); - return current; - }, + 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); + } - set current(value) { - if (currentlyRenderingFiber$1 !== null && !didWarnAboutWrite) { - if (hasBeenInitialized || !didCheckForLazyInit) { - didWarnAboutWrite = true; + var error$1 = errorInfo.value; + var stack = errorInfo.stack; + this.componentDidCatch(error$1, { + componentStack: stack !== null ? stack : "" + }); - warn( - "%s: Unsafe write of a mutable value during render.\n\n" + - "Writing to a ref during render is only safe if the ref holds " + - "a lazily-initialized value that is only set once.\n", - getComponentNameFromFiber(currentlyRenderingFiber$1) || - "Unknown" - ); - } + { + if (typeof getDerivedStateFromError !== "function") { + // If componentDidCatch is the only error boundary method defined, + // then it needs to call setState to recover from errors. + // If no state update is scheduled then the boundary will swallow the error. + if (!includesSomeLane(fiber.lanes, SyncLane)) { + error( + "%s: Error boundaries should implement getDerivedStateFromError(). " + + "In that method, return a state update to display an error message or fallback UI.", + getComponentNameFromFiber(fiber) || "Unknown" + ); } - - hasBeenInitialized = true; - current = value; } - }; - Object.seal(ref); - hook.memoizedState = ref; - return ref; - } - } else { - var _ref2 = { - current: initialValue + } }; - hook.memoizedState = _ref2; - return _ref2; } -} - -function updateRef(initialValue) { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; -} -function mountEffectImpl(fiberFlags, hookFlags, create, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - currentlyRenderingFiber$1.flags |= fiberFlags; - hook.memoizedState = pushEffect( - HasEffect | hookFlags, - create, - undefined, - nextDeps - ); + return update; } -function updateEffectImpl(fiberFlags, hookFlags, create, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var destroy = undefined; // currentHook is null when rerendering after a render phase state update. - - if (currentHook !== null) { - var prevEffect = currentHook.memoizedState; - destroy = prevEffect.destroy; - - if (nextDeps !== null) { - var prevDeps = prevEffect.deps; +function resetSuspendedComponent(sourceFiber, rootRenderLanes) { + if (enableLazyContextPropagation) { + var currentSourceFiber = sourceFiber.alternate; - if (areHookInputsEqual(nextDeps, prevDeps)) { - hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps); - return; - } + if (currentSourceFiber !== null) { + // Since we never visited the children of the suspended component, we + // need to propagate the context change now, to ensure that we visit + // them during the retry. + // + // We don't have to do this for errors because we retry errors without + // committing in between. So this is specific to Suspense. + propagateParentContextChangesToDeferredTree( + currentSourceFiber, + sourceFiber, + rootRenderLanes + ); } - } - - currentlyRenderingFiber$1.flags |= fiberFlags; - hook.memoizedState = pushEffect( - HasEffect | hookFlags, - create, - destroy, - nextDeps - ); -} - -function mountEffect(create, deps) { - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - mountEffectImpl( - MountPassiveDev | Passive$1 | PassiveStatic, - Passive, - create, - deps - ); - } else { - mountEffectImpl(Passive$1 | PassiveStatic, Passive, create, deps); - } -} - -function updateEffect(create, deps) { - updateEffectImpl(Passive$1, Passive, create, deps); -} + } // Reset the memoizedState to what it was before we attempted to render it. + // A legacy mode Suspense quirk, only relevant to hook components. -function useEffectEventImpl(payload) { - currentlyRenderingFiber$1.flags |= Update; - var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; + var tag = sourceFiber.tag; - if (componentUpdateQueue === null) { - componentUpdateQueue = createFunctionComponentUpdateQueue(); - currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; - componentUpdateQueue.events = [payload]; - } else { - var events = componentUpdateQueue.events; + if ( + (sourceFiber.mode & ConcurrentMode) === NoMode && + (tag === FunctionComponent || + tag === ForwardRef || + tag === SimpleMemoComponent) + ) { + var currentSource = sourceFiber.alternate; - if (events === null) { - componentUpdateQueue.events = [payload]; + if (currentSource) { + sourceFiber.updateQueue = currentSource.updateQueue; + sourceFiber.memoizedState = currentSource.memoizedState; + sourceFiber.lanes = currentSource.lanes; } else { - events.push(payload); + sourceFiber.updateQueue = null; + sourceFiber.memoizedState = null; } } } -function mountEvent(callback) { - var hook = mountWorkInProgressHook(); - var ref = { - impl: callback - }; - hook.memoizedState = ref; // $FlowIgnore[incompatible-return] +function markSuspenseBoundaryShouldCapture( + suspenseBoundary, + returnFiber, + sourceFiber, + root, + rootRenderLanes +) { + // This marks a Suspense boundary so that when we're unwinding the stack, + // it captures the suspended "exception" and does a second (fallback) pass. + if ((suspenseBoundary.mode & ConcurrentMode) === NoMode) { + // Legacy Mode Suspense + // + // If the boundary is in legacy mode, we should *not* + // suspend the commit. Pretend as if the suspended component rendered + // null and keep rendering. When the Suspense boundary completes, + // we'll do a second pass to render the fallback. + if (suspenseBoundary === returnFiber) { + // Special case where we suspended while reconciling the children of + // a Suspense boundary's inner Offscreen wrapper fiber. This happens + // when a React.lazy component is a direct child of a + // Suspense boundary. + // + // Suspense boundaries are implemented as multiple fibers, but they + // are a single conceptual unit. The legacy mode behavior where we + // pretend the suspended fiber committed as `null` won't work, + // because in this case the "suspended" fiber is the inner + // Offscreen wrapper. + // + // Because the contents of the boundary haven't started rendering + // yet (i.e. nothing in the tree has partially rendered) we can + // switch to the regular, concurrent mode behavior: mark the + // boundary with ShouldCapture and enter the unwind phase. + suspenseBoundary.flags |= ShouldCapture; + } else { + suspenseBoundary.flags |= DidCapture; + sourceFiber.flags |= ForceUpdateForLegacySuspense; // 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. - return function eventFn() { - if (isInvalidExecutionContextForEventFunction()) { - throw new Error( - "A function wrapped in useEffectEvent can't be called during rendering." - ); - } + sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete); - return ref.impl.apply(undefined, arguments); - }; -} + if (sourceFiber.tag === ClassComponent) { + var currentSourceFiber = sourceFiber.alternate; -function updateEvent(callback) { - var hook = updateWorkInProgressHook(); - var ref = hook.memoizedState; - useEffectEventImpl({ - ref: ref, - nextImpl: callback - }); // $FlowIgnore[incompatible-return] + 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 update to + // prevent a bail out. + var update = createUpdate(SyncLane); + update.tag = ForceUpdate; + enqueueUpdate(sourceFiber, update, SyncLane); + } + } // The source fiber did not complete. Mark it with Sync priority to + // indicate that it still has pending work. - return function eventFn() { - if (isInvalidExecutionContextForEventFunction()) { - throw new Error( - "A function wrapped in useEffectEvent can't be called during rendering." - ); + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); } - return ref.impl.apply(undefined, arguments); - }; -} + return suspenseBoundary; + } // Confirmed that the boundary is in a concurrent mode tree. Continue + // with the normal suspend path. + // + // After this we'll use a set of heuristics to determine whether this + // render pass will run to completion or restart or "suspend" the commit. + // The actual logic for this is spread out in different places. + // + // This first principle is that if we're going to suspend when we complete + // a root, then we should also restart if we get an update or ping that + // might unsuspend it, and vice versa. The only reason to suspend is + // because you think you might want to restart before committing. However, + // it doesn't make sense to restart only while in the period we're suspended. + // + // Restarting too aggressively is also not good because it starves out any + // intermediate loading state. So we use heuristics to determine when. + // Suspense Heuristics + // + // If nothing threw a Promise or all the same fallbacks are already showing, + // then don't suspend/restart. + // + // If this is an initial render of a new tree of Suspense boundaries and + // those trigger a fallback, then don't suspend/restart. We want to ensure + // that we can show the initial loading state as quickly as possible. + // + // If we hit a "Delayed" case, such as when we'd switch from content back into + // a fallback, then we should always suspend/restart. Transitions apply + // to this case. If none is defined, JND is used instead. + // + // If we're already showing a fallback and it gets "retried", allowing us to show + // another level, but there's still an inner boundary that would show a fallback, + // then we suspend/restart for 500ms since the last time we showed a fallback + // anywhere in the tree. This effectively throttles progressive loading into a + // consistent train of commits. This also gives us an opportunity to restart to + // get to the completed state slightly earlier. + // + // If there's ambiguity due to batching it's resolved in preference of: + // 1) "delayed", 2) "initial render", 3) "retry". + // + // We want to ensure that a "busy" state doesn't get force committed. We want to + // ensure that new initial loading states can commit as soon as possible. -function mountInsertionEffect(create, deps) { - mountEffectImpl(Update, Insertion, create, deps); -} + suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in + // the begin phase to prevent an early bailout. -function updateInsertionEffect(create, deps) { - return updateEffectImpl(Update, Insertion, create, deps); + suspenseBoundary.lanes = rootRenderLanes; + return suspenseBoundary; } -function mountLayoutEffect(create, deps) { - var fiberFlags = Update | LayoutStatic; +function throwException( + root, + returnFiber, + sourceFiber, + value, + rootRenderLanes +) { + // The source fiber did not complete. + sourceFiber.flags |= Incomplete; - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, rootRenderLanes); + } } - return mountEffectImpl(fiberFlags, Layout, create, deps); -} - -function updateLayoutEffect(create, deps) { - return updateEffectImpl(Update, Layout, 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; + if ( + value !== null && + typeof value === "object" && + typeof value.then === "function" + ) { + // This is a wakeable. The component suspended. + var wakeable = value; + resetSuspendedComponent(sourceFiber, rootRenderLanes); { - if (!refObject.hasOwnProperty("current")) { - error( - "Expected useImperativeHandle() first argument to either be a " + - "ref callback or React.createRef() object. Instead received: %s.", - "an object with keys {" + Object.keys(refObject).join(", ") + "}" - ); + if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) { + markDidThrowWhileHydratingDEV(); } } - var _inst = create(); + { + if (enableDebugTracing) { + if (sourceFiber.mode & DebugTracingMode) { + var name = getComponentNameFromFiber(sourceFiber) || "Unknown"; + logComponentSuspended(name, wakeable); + } + } + } // Mark the nearest Suspense boundary to switch to rendering a fallback. - refObject.current = _inst; - return function () { - refObject.current = null; - }; - } -} - -function mountImperativeHandle(ref, create, deps) { - { - if (typeof create !== "function") { - error( - "Expected useImperativeHandle() second argument to be a function " + - "that creates a handle. Instead received: %s.", - create !== null ? typeof create : "null" - ); - } - } // TODO: If deps are provided, should we skip comparing the ref itself? - - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - var fiberFlags = Update | LayoutStatic; + var suspenseBoundary = getSuspenseHandler(); - if ((currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } + if (suspenseBoundary !== null) { + switch (suspenseBoundary.tag) { + case SuspenseComponent: { + // If this suspense boundary is not already showing a fallback, mark + // the in-progress render as suspended. We try to perform this logic + // as soon as soon as possible during the render phase, so the work + // loop can know things like whether it's OK to switch to other tasks, + // or whether it can wait for data to resolve before continuing. + // TODO: Most of these checks are already performed when entering a + // Suspense boundary. We should track the information on the stack so + // we don't have to recompute it on demand. This would also allow us + // to unify with `use` which needs to perform this logic even sooner, + // before `throwException` is called. + if (sourceFiber.mode & ConcurrentMode) { + if (getShellBoundary() === null) { + // Suspended in the "shell" of the app. This is an undesirable + // loading state. We should avoid committing this tree. + renderDidSuspendDelayIfPossible(); + } else { + // If we suspended deeper than the shell, we don't need to delay + // the commmit. However, we still call renderDidSuspend if this is + // a new boundary, to tell the work loop that a new fallback has + // appeared during this render. + // TODO: Theoretically we should be able to delete this branch. + // It's currently used for two things: 1) to throttle the + // appearance of successive loading states, and 2) in + // SuspenseList, to determine whether the children include any + // pending fallbacks. For 1, we should apply throttling to all + // retries, not just ones that render an additional fallback. For + // 2, we should check subtreeFlags instead. Then we can delete + // this branch. + var current = suspenseBoundary.alternate; - mountEffectImpl( - fiberFlags, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); -} + if (current === null) { + renderDidSuspend(); + } + } + } -function updateImperativeHandle(ref, create, deps) { - { - if (typeof create !== "function") { - error( - "Expected useImperativeHandle() second argument to be a function " + - "that creates a handle. Instead received: %s.", - create !== null ? typeof create : "null" - ); - } - } // TODO: If deps are provided, should we skip comparing the ref itself? + suspenseBoundary.flags &= ~ForceClientRender; + markSuspenseBoundaryShouldCapture( + suspenseBoundary, + returnFiber, + sourceFiber, + root, + rootRenderLanes + ); // Retry listener + // + // If the fallback does commit, we need to attach a different type of + // listener. This one schedules an update on the Suspense boundary to + // turn the fallback state off. + // + // Stash the wakeable on the boundary fiber so we can access it in the + // commit phase. + // + // When the wakeable resolves, we'll attempt to render the boundary + // again ("retry"). - var effectDeps = - deps !== null && deps !== undefined ? deps.concat([ref]) : null; - updateEffectImpl( - Update, - Layout, - imperativeHandleEffect.bind(null, create, ref), - effectDeps - ); -} + var wakeables = suspenseBoundary.updateQueue; -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. -} + if (wakeables === null) { + suspenseBoundary.updateQueue = new Set([wakeable]); + } else { + wakeables.add(wakeable); + } -var updateDebugValue = mountDebugValue; + break; + } -function mountCallback(callback, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - hook.memoizedState = [callback, nextDeps]; - return callback; -} + case OffscreenComponent: { + if (suspenseBoundary.mode & ConcurrentMode) { + suspenseBoundary.flags |= ShouldCapture; + var offscreenQueue = suspenseBoundary.updateQueue; -function updateCallback(callback, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var prevState = hook.memoizedState; + if (offscreenQueue === null) { + var newOffscreenQueue = { + transitions: null, + markerInstances: null, + wakeables: new Set([wakeable]) + }; + suspenseBoundary.updateQueue = newOffscreenQueue; + } else { + var _wakeables = offscreenQueue.wakeables; - if (nextDeps !== null) { - var prevDeps = prevState[1]; + if (_wakeables === null) { + offscreenQueue.wakeables = new Set([wakeable]); + } else { + _wakeables.add(wakeable); + } + } - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; - } - } + break; + } + } + // eslint-disable-next-line no-fallthrough - hook.memoizedState = [callback, nextDeps]; - return callback; -} + default: { + throw new Error( + "Unexpected Suspense handler tag (" + + suspenseBoundary.tag + + "). This " + + "is a bug in React." + ); + } + } // We only attach ping listeners in concurrent mode. Legacy Suspense always + // commits fallbacks synchronously, so there are no pings. -function mountMemo(nextCreate, deps) { - var hook = mountWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; + if (suspenseBoundary.mode & ConcurrentMode) { + attachPingListener(root, wakeable, rootRenderLanes); + } - if (shouldDoubleInvokeUserFnsInHooksDEV) { - nextCreate(); - } + return; + } else { + // No boundary was found. Unless this is a sync update, this is OK. + // We can suspend and wait for more data to arrive. + if (root.tag === ConcurrentRoot) { + // In a concurrent root, suspending without a Suspense boundary is + // allowed. It will suspend indefinitely without committing. + // + // TODO: Should we have different behavior for discrete updates? What + // about flushSync? Maybe it should put the tree into an inert state, + // and potentially log a warning. Revisit this for a future release. + attachPingListener(root, wakeable, rootRenderLanes); + renderDidSuspendDelayIfPossible(); + return; + } else { + // In a legacy root, suspending without a boundary is always an error. + var uncaughtSuspenseError = new Error( + "A component suspended while responding to synchronous input. This " + + "will cause the UI to be replaced with a loading indicator. To " + + "fix, updates that suspend should be wrapped " + + "with startTransition." + ); + value = uncaughtSuspenseError; + } + } + } else { + // This is a regular error, not a Suspense wakeable. + if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) { + markDidThrowWhileHydratingDEV(); - var nextValue = nextCreate(); - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; -} + var _suspenseBoundary = getSuspenseHandler(); // If the error was thrown during hydration, we may be able to recover by + // discarding the dehydrated content and switching to a client render. + // Instead of surfacing the error, find the nearest Suspense boundary + // and render it again without hydration. -function updateMemo(nextCreate, deps) { - var hook = updateWorkInProgressHook(); - var nextDeps = deps === undefined ? null : deps; - var prevState = hook.memoizedState; // Assume these are defined. If they're not, areHookInputsEqual will warn. + if (_suspenseBoundary !== null) { + if ((_suspenseBoundary.flags & ShouldCapture) === NoFlags$1) { + // Set a flag to indicate that we should try rendering the normal + // children again, not the fallback. + _suspenseBoundary.flags |= ForceClientRender; + } - if (nextDeps !== null) { - var prevDeps = prevState[1]; + markSuspenseBoundaryShouldCapture( + _suspenseBoundary, + returnFiber, + sourceFiber, + root, + rootRenderLanes + ); // Even though the user may not be affected by this error, we should + // still log it so it can be fixed. - if (areHookInputsEqual(nextDeps, prevDeps)) { - return prevState[0]; + queueHydrationError(createCapturedValueAtFiber(value, sourceFiber)); + return; + } } } - if (shouldDoubleInvokeUserFnsInHooksDEV) { - nextCreate(); - } + value = createCapturedValueAtFiber(value, sourceFiber); + renderDidError(value); // 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. - var nextValue = nextCreate(); - hook.memoizedState = [nextValue, nextDeps]; - return nextValue; -} + var workInProgress = returnFiber; -function mountDeferredValue(value) { - var hook = mountWorkInProgressHook(); - hook.memoizedState = value; - return value; -} + do { + switch (workInProgress.tag) { + case HostRoot: { + var _errorInfo = value; + workInProgress.flags |= ShouldCapture; + var lane = pickArbitraryLane(rootRenderLanes); + workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); + var update = createRootErrorUpdate(workInProgress, _errorInfo, lane); + enqueueCapturedUpdate(workInProgress, update); + return; + } -function updateDeferredValue(value) { - var hook = updateWorkInProgressHook(); - var resolvedCurrentHook = currentHook; - var prevValue = resolvedCurrentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value); -} + case ClassComponent: + // Capture and retry + var errorInfo = value; + var ctor = workInProgress.type; + var instance = workInProgress.stateNode; -function rerenderDeferredValue(value) { - var hook = updateWorkInProgressHook(); + if ( + (workInProgress.flags & DidCapture) === NoFlags$1 && + (typeof ctor.getDerivedStateFromError === "function" || + (instance !== null && + typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance))) + ) { + workInProgress.flags |= ShouldCapture; - if (currentHook === null) { - // This is a rerender during a mount. - hook.memoizedState = value; - return value; - } else { - // This is a rerender during an update. - var prevValue = currentHook.memoizedState; - return updateDeferredValueImpl(hook, prevValue, value); - } -} + var _lane = pickArbitraryLane(rootRenderLanes); -function updateDeferredValueImpl(hook, prevValue, value) { - var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes$1); + workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); // Schedule the error boundary to re-render using updated state - if (shouldDeferValue) { - // This is an urgent update. If the value has changed, keep using the - // previous value and spawn a deferred render to update it later. - if (!objectIs(value, prevValue)) { - // Schedule a deferred render - var deferredLane = claimNextTransitionLane(); - currentlyRenderingFiber$1.lanes = mergeLanes( - currentlyRenderingFiber$1.lanes, - deferredLane - ); - markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent - // from the latest value. The name "baseState" doesn't really match how we - // use it because we're reusing a state hook field instead of creating a - // new one. + var _update = createClassErrorUpdate( + workInProgress, + errorInfo, + _lane + ); - hook.baseState = true; - } // Reuse the previous value + enqueueCapturedUpdate(workInProgress, _update); + return; + } - return prevValue; - } else { - // This is not an urgent update, so we can use the latest value regardless - // of what it is. No need to defer it. - // However, if we're currently inside a spawned render, then we need to mark - // this as an update to prevent the fiber from bailing out. - // - // `baseState` is true when the current value is different from the rendered - // value. The name doesn't really match how we use it because we're reusing - // a state hook field instead of creating a new one. - if (hook.baseState) { - // Flip this back to false. - hook.baseState = false; - markWorkInProgressReceivedUpdate(); - } + break; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - hook.memoizedState = value; - return value; - } + workInProgress = workInProgress.return; + } while (workInProgress !== null); } -function startTransition(setPending, callback, options) { - var previousPriority = getCurrentUpdatePriority$1(); - setCurrentUpdatePriority( - higherEventPriority(previousPriority, ContinuousEventPriority) - ); - setPending(true); - var prevTransition = ReactCurrentBatchConfig$2.transition; - ReactCurrentBatchConfig$2.transition = {}; - var currentTransition = ReactCurrentBatchConfig$2.transition; - +var TransitionRoot = 0; +var TransitionTracingMarker = 1; +function processTransitionCallbacks(pendingTransitions, endTime, callbacks) { if (enableTransitionTracing) { - if (options !== undefined && options.name !== undefined) { - ReactCurrentBatchConfig$2.transition.name = options.name; - ReactCurrentBatchConfig$2.transition.startTime = now$1(); - } - } + if (pendingTransitions !== null) { + var transitionStart = pendingTransitions.transitionStart; + var onTransitionStart = callbacks.onTransitionStart; - { - ReactCurrentBatchConfig$2.transition._updatedFibers = new Set(); - } + if (transitionStart !== null && onTransitionStart != null) { + transitionStart.forEach(function (transition) { + return onTransitionStart(transition.name, transition.startTime); + }); + } - try { - setPending(false); - callback(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig$2.transition = prevTransition; + var markerProgress = pendingTransitions.markerProgress; + var onMarkerProgress = callbacks.onMarkerProgress; - { - if (prevTransition === null && currentTransition._updatedFibers) { - var updatedFibersCount = currentTransition._updatedFibers.size; + if (onMarkerProgress != null && markerProgress !== null) { + markerProgress.forEach(function (markerInstance, markerName) { + if (markerInstance.transitions !== null) { + // TODO: Clone the suspense object so users can't modify it + var pending = + markerInstance.pendingBoundaries !== null + ? Array.from(markerInstance.pendingBoundaries.values()) + : []; + markerInstance.transitions.forEach(function (transition) { + onMarkerProgress( + transition.name, + markerName, + transition.startTime, + endTime, + pending + ); + }); + } + }); + } - currentTransition._updatedFibers.clear(); + var markerComplete = pendingTransitions.markerComplete; + var onMarkerComplete = callbacks.onMarkerComplete; - if (updatedFibersCount > 10) { - warn( - "Detected a large number of updates inside startTransition. " + - "If this is due to a subscription please re-write it to use React provided hooks. " + - "Otherwise concurrent mode guarantees are off the table." - ); - } + if (markerComplete !== null && onMarkerComplete != null) { + markerComplete.forEach(function (transitions, markerName) { + transitions.forEach(function (transition) { + onMarkerComplete( + transition.name, + markerName, + transition.startTime, + endTime + ); + }); + }); } - } - } -} - -function mountTransition() { - var _mountState = mountState(false), - isPending = _mountState[0], - setPending = _mountState[1]; // The `start` method never changes. - var start = startTransition.bind(null, setPending); - var hook = mountWorkInProgressHook(); - hook.memoizedState = start; - return [isPending, start]; -} + var markerIncomplete = pendingTransitions.markerIncomplete; + var onMarkerIncomplete = callbacks.onMarkerIncomplete; -function updateTransition() { - var _updateState = updateState(), - isPending = _updateState[0]; + if (onMarkerIncomplete != null && markerIncomplete !== null) { + markerIncomplete.forEach(function (_ref, markerName) { + var transitions = _ref.transitions, + aborts = _ref.aborts; + transitions.forEach(function (transition) { + var filteredAborts = []; + aborts.forEach(function (abort) { + switch (abort.reason) { + case "marker": { + filteredAborts.push({ + type: "marker", + name: abort.name, + endTime: endTime + }); + break; + } - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - return [isPending, start]; -} + case "suspense": { + filteredAborts.push({ + type: "suspense", + name: abort.name, + endTime: endTime + }); + break; + } + } + }); -function rerenderTransition() { - var _rerenderState = rerenderState(), - isPending = _rerenderState[0]; + if (filteredAborts.length > 0) { + onMarkerIncomplete( + transition.name, + markerName, + transition.startTime, + filteredAborts + ); + } + }); + }); + } - var hook = updateWorkInProgressHook(); - var start = hook.memoizedState; - return [isPending, start]; -} + var transitionProgress = pendingTransitions.transitionProgress; + var onTransitionProgress = callbacks.onTransitionProgress; -function mountId() { - var hook = mountWorkInProgressHook(); - var root = getWorkInProgressRoot(); // TODO: In Fizz, id generation is specific to each server config. Maybe we - // should do this in Fiber, too? Deferring this decision for now because - // there's no other place to store the prefix except for an internal field on - // the public createRoot object, which the fiber tree does not currently have - // a reference to. + if (onTransitionProgress != null && transitionProgress !== null) { + transitionProgress.forEach(function (pending, transition) { + onTransitionProgress( + transition.name, + transition.startTime, + endTime, + Array.from(pending.values()) + ); + }); + } - var identifierPrefix = root.identifierPrefix; - var id; + var transitionComplete = pendingTransitions.transitionComplete; + var onTransitionComplete = callbacks.onTransitionComplete; - if (getIsHydrating()) { - var treeId = getTreeId(); // Use a captial R prefix for server-generated ids. - - id = ":" + identifierPrefix + "R" + treeId; // Unless this is the first id at this level, append a number at the end - // that represents the position of this useId hook among all the useId - // hooks for this fiber. + if (transitionComplete !== null && onTransitionComplete != null) { + transitionComplete.forEach(function (transition) { + return onTransitionComplete( + transition.name, + transition.startTime, + endTime + ); + }); + } + } + } +} // For every tracing marker, store a pointer to it. We will later access it +// to get the set of suspense boundaries that need to resolve before the +// tracing marker can be logged as complete +// This code lives separate from the ReactFiberTransition code because +// we push and pop on the tracing marker, not the suspense boundary - var localId = localIdCounter++; +var markerInstanceStack = createCursor(null); +function pushRootMarkerInstance(workInProgress) { + if (enableTransitionTracing) { + // On the root, every transition gets mapped to it's own map of + // suspense boundaries. The transition is marked as complete when + // the suspense boundaries map is empty. We do this because every + // transition completes at different times and depends on different + // suspense boundaries to complete. We store all the transitions + // along with its map of suspense boundaries in the root incomplete + // transitions map. Each entry in this map functions like a tracing + // marker does, so we can push it onto the marker instance stack + var transitions = getWorkInProgressTransitions(); + var root = workInProgress.stateNode; - if (localId > 0) { - id += "H" + localId.toString(32); + if (transitions !== null) { + transitions.forEach(function (transition) { + if (!root.incompleteTransitions.has(transition)) { + var markerInstance = { + tag: TransitionRoot, + transitions: new Set([transition]), + pendingBoundaries: null, + aborts: null, + name: null + }; + root.incompleteTransitions.set(transition, markerInstance); + } + }); } - id += ":"; - } else { - // Use a lowercase r prefix for client-generated ids. - var globalClientId = globalClientIdCounter++; - id = ":" + identifierPrefix + "r" + globalClientId.toString(32) + ":"; - } + var markerInstances = []; // For ever transition on the suspense boundary, we push the transition + // along with its map of pending suspense boundaries onto the marker + // instance stack. - hook.memoizedState = id; - return id; + root.incompleteTransitions.forEach(function (markerInstance) { + markerInstances.push(markerInstance); + }); + push(markerInstanceStack, markerInstances, workInProgress); + } } - -function updateId() { - var hook = updateWorkInProgressHook(); - var id = hook.memoizedState; - return id; +function popRootMarkerInstance(workInProgress) { + if (enableTransitionTracing) { + pop(markerInstanceStack, workInProgress); + } } - -function mountRefresh() { - var hook = mountWorkInProgressHook(); - var refresh = (hook.memoizedState = refreshCache.bind( - null, - currentlyRenderingFiber$1 - )); - return refresh; +function pushMarkerInstance(workInProgress, markerInstance) { + if (enableTransitionTracing) { + if (markerInstanceStack.current === null) { + push(markerInstanceStack, [markerInstance], workInProgress); + } else { + push( + markerInstanceStack, + markerInstanceStack.current.concat(markerInstance), + workInProgress + ); + } + } } - -function updateRefresh() { - var hook = updateWorkInProgressHook(); - return hook.memoizedState; +function popMarkerInstance(workInProgress) { + if (enableTransitionTracing) { + pop(markerInstanceStack, workInProgress); + } } +function getMarkerInstances() { + if (enableTransitionTracing) { + return markerInstanceStack.current; + } -function refreshCache(fiber, seedKey, seedValue) { - // TODO: Consider warning if the refresh is at discrete priority, or if we - // otherwise suspect that it wasn't batched properly. - - var provider = fiber.return; + return null; +} - while (provider !== null) { - switch (provider.tag) { - case CacheComponent: - case HostRoot: { - // Schedule an update on the cache boundary to trigger a refresh. - var lane = requestUpdateLane(provider); - var refreshUpdate = createUpdate(lane); - var root = enqueueUpdate(provider, refreshUpdate, lane); +var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows +// into a dehydrated boundary. - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, provider, lane, eventTime); - entangleTransitions(root, provider, lane); - } // TODO: If a refresh never commits, the new cache created here must be - // released. A simple case is start refreshing a cache boundary, but then - // unmount that boundary before the refresh completes. +var SelectiveHydrationException = new Error( + "This is not a real error. It's an implementation detail of React's " + + "selective hydration feature. If this leaks into userspace, it's a bug in " + + "React. Please file an issue." +); +var didReceiveUpdate = false; +var didWarnAboutBadClass; +var didWarnAboutModulePatternComponent; +var didWarnAboutContextTypeOnFunctionComponent; +var didWarnAboutGetDerivedStateOnFunctionComponent; +var didWarnAboutFunctionRefs; +var didWarnAboutReassigningProps; +var didWarnAboutRevealOrder; +var didWarnAboutTailOptions; +var didWarnAboutDefaultPropsOnFunctionComponent; - var seededCache = createCache(); +{ + didWarnAboutBadClass = {}; + didWarnAboutModulePatternComponent = {}; + didWarnAboutContextTypeOnFunctionComponent = {}; + didWarnAboutGetDerivedStateOnFunctionComponent = {}; + didWarnAboutFunctionRefs = {}; + didWarnAboutReassigningProps = false; + didWarnAboutRevealOrder = {}; + didWarnAboutTailOptions = {}; + didWarnAboutDefaultPropsOnFunctionComponent = {}; +} - if (seedKey !== null && seedKey !== undefined && root !== null) { - { - // Seed the cache with the value passed by the caller. This could be - // from a server mutation, or it could be a streaming response. - seededCache.data.set(seedKey, seedValue); - } - } +function reconcileChildren(current, workInProgress, nextChildren, renderLanes) { + if (current === 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, + renderLanes + ); + } 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.child, + nextChildren, + renderLanes + ); + } +} - var payload = { - cache: seededCache - }; - refreshUpdate.payload = payload; - return; - } - } +function forceUnmountCurrentAndReconcile( + current, + workInProgress, + nextChildren, + renderLanes +) { + // 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.child, + null, + renderLanes + ); // 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 + // identities match. - provider = provider.return; - } // TODO: Warn if unmounted? + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderLanes + ); } -function dispatchReducerAction(fiber, queue, action) { +function updateForwardRef( + current, + workInProgress, + Component, + nextProps, + renderLanes +) { + // 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. { - if (typeof arguments[3] === "function") { - error( - "State updates from the useState() and useReducer() Hooks don't support the " + - "second callback argument. To execute a side effect after " + - "rendering, declare it in the component body with useEffect()." - ); + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(Component) + ); + } } } - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + var render = Component.render; + var ref = workInProgress.ref; // The rest is a fork of updateFunctionComponent - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); + var nextChildren; + var hasId; + prepareToReadContext(workInProgress, renderLanes); - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitionUpdate(root, queue, lane); - } + if (enableSchedulingProfiler) { + markComponentRenderStarted(workInProgress); } - markUpdateInDevTools(fiber, lane, action); -} - -function dispatchSetState(fiber, queue, action) { { - if (typeof arguments[3] === "function") { - error( - "State updates from the useState() and useReducer() Hooks don't support the " + - "second callback argument. To execute a side effect after " + - "rendering, declare it in the component body with useEffect()." - ); - } + ReactCurrentOwner$2.current = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks( + current, + workInProgress, + render, + nextProps, + ref, + renderLanes + ); + hasId = checkDidRenderIdHook(); + setIsRendering(false); } - var lane = requestUpdateLane(fiber); - var update = { - lane: lane, - action: action, - hasEagerState: false, - eagerState: null, - next: null - }; + if (enableSchedulingProfiler) { + markComponentRenderStopped(); + } - if (isRenderPhaseUpdate(fiber)) { - enqueueRenderPhaseUpdate(queue, update); - } else { - var alternate = fiber.alternate; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } + + if (getIsHydrating() && hasId) { + pushMaterializedTreeId(workInProgress); + } // React DevTools reads this flag. + + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} + +function updateMemoComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes +) { + if (current === null) { + var type = Component.type; if ( - fiber.lanes === NoLanes && - (alternate === null || alternate.lanes === NoLanes) + isSimpleFunctionComponent(type) && + Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. + Component.defaultProps === undefined ) { - // 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; + var resolvedType = type; - if (lastRenderedReducer !== null) { - var prevDispatcher; + { + resolvedType = resolveFunctionForHotReloading(type); + } // 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. - { - prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; - } + workInProgress.tag = SimpleMemoComponent; + workInProgress.type = resolvedType; - 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. + { + validateFunctionComponentInDev(workInProgress, type); + } - update.hasEagerState = true; - update.eagerState = eagerState; + return updateSimpleMemoComponent( + current, + workInProgress, + resolvedType, + nextProps, + renderLanes + ); + } - if (objectIs(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. - // TODO: Do we still need to entangle transitions in this case? - enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update); - return; - } - } catch (error) { - // Suppress the error. It will throw again in the render phase. - } finally { - { - ReactCurrentDispatcher$1.current = prevDispatcher; - } + { + var innerPropTypes = type.propTypes; + + if (innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(type) + ); + } + + if (Component.defaultProps !== undefined) { + var componentName = getComponentNameFromType(type) || "Unknown"; + + if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { + error( + "%s: Support for defaultProps will be removed from memo components " + + "in a future major release. Use JavaScript default parameters instead.", + componentName + ); + + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; } } } - var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane); + var child = createFiberFromTypeAndProps( + Component.type, + null, + nextProps, + workInProgress, + workInProgress.mode, + renderLanes + ); + child.ref = workInProgress.ref; + child.return = workInProgress; + workInProgress.child = child; + return child; + } - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitionUpdate(root, queue, lane); + { + var _type = Component.type; + var _innerPropTypes = _type.propTypes; + + if (_innerPropTypes) { + // Inner memo component props aren't currently validated in createElement. + // We could move it there, but we'd still need this for lazy code path. + checkPropTypes( + _innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(_type) + ); } } - markUpdateInDevTools(fiber, lane, action); -} + var currentChild = current.child; // This is always exactly one child -function isRenderPhaseUpdate(fiber) { - var alternate = fiber.alternate; - return ( - fiber === currentlyRenderingFiber$1 || - (alternate !== null && alternate === currentlyRenderingFiber$1) + var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( + current, + renderLanes ); -} -function enqueueRenderPhaseUpdate(queue, update) { - // 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. - didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = - true; - var pending = queue.pending; + if (!hasScheduledUpdateOrContext) { + // 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 - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + var compare = Component.compare; + compare = compare !== null ? compare : shallowEqual; - queue.pending = update; -} // TODO: Move to ReactFiberConcurrentUpdates? + if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } + } // React DevTools reads this flag. -function entangleTransitionUpdate(root, queue, lane) { - if (isTransitionLane(lane)) { - var queueLanes = queue.lanes; // If any entangled lanes are no longer pending on the root, then they - // must have finished. We can remove them from the shared queue, which - // represents a superset of the actually pending lanes. In some cases we - // may entangle more than we need to, but that's OK. In fact it's worse if - // we *don't* entangle when we should. + workInProgress.flags |= PerformedWork; + var newChild = createWorkInProgress(currentChild, nextProps); + newChild.ref = workInProgress.ref; + newChild.return = workInProgress; + workInProgress.child = newChild; + return newChild; +} - queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. +function updateSimpleMemoComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes +) { + // 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 (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var outerMemoType = workInProgress.elementType; - var newQueueLanes = mergeLanes(queueLanes, lane); - queue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if - // the lane finished since the last time we entangled it. So we need to - // entangle it again, just to be sure. + if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { + // We warn when you define propTypes on lazy() + // so let's just skip over it to find memo() outer wrapper. + // Inner props for memo are validated later. + var lazyComponent = outerMemoType; + var payload = lazyComponent._payload; + var init = lazyComponent._init; - markRootEntangled(root, newQueueLanes); - } -} + try { + outerMemoType = init(payload); + } catch (x) { + outerMemoType = null; + } // Inner propTypes will be validated in the function component path. -function markUpdateInDevTools(fiber, lane, action) { - { - if (enableDebugTracing) { - if (fiber.mode & DebugTracingMode) { - var name = getComponentNameFromFiber(fiber) || "Unknown"; - logStateUpdateScheduled(name, lane, action); + var outerPropTypes = outerMemoType && outerMemoType.propTypes; + + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + nextProps, // Resolved (SimpleMemoComponent has no defaultProps) + "prop", + getComponentNameFromType(outerMemoType) + ); + } } } } - if (enableSchedulingProfiler) { - markStateUpdateScheduled(fiber, lane); + if (current !== null) { + var prevProps = current.memoizedProps; + + if ( + shallowEqual(prevProps, nextProps) && + current.ref === workInProgress.ref && // Prevent bailout if the implementation changed due to hot reload. + workInProgress.type === current.type + ) { + didReceiveUpdate = false; // The props are shallowly equal. Reuse the previous props object, like we + // would during a normal fiber bailout. + // + // We don't have strong guarantees that the props object is referentially + // equal during updates where we can't bail out anyway — like if the props + // are shallowly equal, but there's a local state or context update in the + // same batch. + // + // However, as a principle, we should aim to make the behavior consistent + // across different ways of memoizing a component. For example, React.memo + // has a different internal Fiber layout if you pass a normal function + // component (SimpleMemoComponent) versus if you pass a different type + // like forwardRef (MemoComponent). But this is an implementation detail. + // Wrapping a component in forwardRef (or React.lazy, etc) shouldn't + // affect whether the props object is reused during a bailout. + + workInProgress.pendingProps = nextProps = prevProps; + + if (!checkScheduledUpdateOrContext(current, renderLanes)) { + // The pending lanes were cleared at the beginning of beginWork. We're + // about to bail out, but there might be other lanes that weren't + // included in the current render. Usually, the priority level of the + // remaining updates is accumulated during the evaluation of the + // component (i.e. when processing the update queue). But since since + // we're bailing out early *without* evaluating the component, we need + // to account for it here, too. Reset to the value of the current fiber. + // NOTE: This only applies to SimpleMemoComponent, not MemoComponent, + // because a MemoComponent fiber does not have hooks or an update queue; + // rather, it wraps around an inner component, which may or may not + // contains hooks. + // TODO: Move the reset at in beginWork out of the common path so that + // this is no longer necessary. + workInProgress.lanes = current.lanes; + return bailoutOnAlreadyFinishedWork( + current, + workInProgress, + renderLanes + ); + } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { + // This is a special case that only exists for legacy mode. + // See https://github.com/facebook/react/pull/19216. + didReceiveUpdate = true; + } + } } + + return updateFunctionComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes + ); } -var ContextOnlyDispatcher = { - readContext: readContext, - useCallback: throwInvalidHookError, - useContext: throwInvalidHookError, - useEffect: throwInvalidHookError, - useImperativeHandle: throwInvalidHookError, - useInsertionEffect: throwInvalidHookError, - useLayoutEffect: throwInvalidHookError, - useMemo: throwInvalidHookError, - useReducer: throwInvalidHookError, - useRef: throwInvalidHookError, - useState: throwInvalidHookError, - useDebugValue: throwInvalidHookError, - useDeferredValue: throwInvalidHookError, - useTransition: throwInvalidHookError, - useMutableSource: throwInvalidHookError, - useSyncExternalStore: throwInvalidHookError, - useId: throwInvalidHookError -}; +function updateOffscreenComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + var nextIsDetached = + (workInProgress.stateNode._pendingVisibility & OffscreenDetached) !== 0; + var prevState = current !== null ? current.memoizedState : null; + markRef$1(current, workInProgress); -{ - ContextOnlyDispatcher.useCacheRefresh = throwInvalidHookError; -} + if ( + nextProps.mode === "hidden" || + nextProps.mode === "unstable-defer-without-hiding" || + nextIsDetached + ) { + // Rendering a hidden tree. + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; -{ - ContextOnlyDispatcher.use = throwInvalidHookError; -} + if (didSuspend) { + // Something suspended inside a hidden tree + // Include the base lanes from the last render + var nextBaseLanes = + prevState !== null + ? mergeLanes(prevState.baseLanes, renderLanes) + : renderLanes; -{ - ContextOnlyDispatcher.useMemoCache = throwInvalidHookError; -} + if (current !== null) { + // Reset to the current children + var currentChild = (workInProgress.child = current.child); // The current render suspended, but there may be other lanes with + // pending work. We can't read `childLanes` from the current Offscreen + // fiber because we reset it when it was deferred; however, we can read + // the pending lanes from the child fibers. -{ - ContextOnlyDispatcher.useEffectEvent = throwInvalidHookError; -} + var currentChildLanes = NoLanes; -var HooksDispatcherOnMountInDEV = null; -var HooksDispatcherOnMountWithHookTypesInDEV = null; -var HooksDispatcherOnUpdateInDEV = null; -var HooksDispatcherOnRerenderInDEV = null; -var InvalidNestedHooksDispatcherOnMountInDEV = null; -var InvalidNestedHooksDispatcherOnUpdateInDEV = null; -var InvalidNestedHooksDispatcherOnRerenderInDEV = null; + while (currentChild !== null) { + currentChildLanes = mergeLanes( + mergeLanes(currentChildLanes, currentChild.lanes), + currentChild.childLanes + ); + currentChild = currentChild.sibling; + } -{ - var warnInvalidContextAccess = function () { - error( - "Context can only be read while React is rendering. " + - "In classes, you can read it in the render method or getDerivedStateFromProps. " + - "In function components, you can read it directly in the function body, but not " + - "inside Hooks like useReducer() or useMemo()." - ); - }; + var lanesWeJustAttempted = nextBaseLanes; + var remainingChildLanes = removeLanes( + currentChildLanes, + lanesWeJustAttempted + ); + workInProgress.childLanes = remainingChildLanes; + } else { + workInProgress.childLanes = NoLanes; + workInProgress.child = null; + } - var warnInvalidHookAccess = function () { - error( - "Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. " + - "You can only call Hooks at the top level of your React function. " + - "For more information, see " + - "https://reactjs.org/link/rules-of-hooks" - ); - }; + return deferHiddenOffscreenComponent( + current, + workInProgress, + nextBaseLanes, + renderLanes + ); + } - HooksDispatcherOnMountInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - mountHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - return mountLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - mountHookTypesDev(); - checkDepsAreArrayDev(deps); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + // In legacy sync mode, don't defer the subtree. Render it now. + // TODO: Consider how Offscreen should work with transitions in the future + var nextState = { + baseLanes: NoLanes, + cachePool: null + }; + workInProgress.memoizedState = nextState; - try { - return mountMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + { + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null, null); + } } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + reuseHiddenContextOnStack(workInProgress); + pushOffscreenSuspenseHandler(workInProgress); + } else if (!includesSomeLane(renderLanes, OffscreenLane)) { + // We're hidden, and we're not rendering at Offscreen. We will bail out + // and resume this tree later. + // Schedule this fiber to re-render at Offscreen priority + workInProgress.lanes = workInProgress.childLanes = + laneToLanes(OffscreenLane); // Include the base lanes from the last render + + var _nextBaseLanes = + prevState !== null + ? mergeLanes(prevState.baseLanes, renderLanes) + : renderLanes; + + return deferHiddenOffscreenComponent( + current, + workInProgress, + _nextBaseLanes, + renderLanes + ); + } else { + // This is the second render. The surrounding visible content has already + // committed. Now we resume rendering the hidden tree. + // Rendering at offscreen, so we can clear the base lanes. + var _nextState = { + baseLanes: NoLanes, + cachePool: null + }; + workInProgress.memoizedState = _nextState; + + if (current !== null) { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should + // be attributed to the transition that spawned it + + pushTransition(workInProgress, prevCachePool, null); + } // Push the lanes that were skipped when we bailed out. + + if (prevState !== null) { + pushHiddenContext(workInProgress, prevState); + } else { + reuseHiddenContextOnStack(workInProgress); } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; - try { - return mountState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + pushOffscreenSuspenseHandler(workInProgress); + } + } else { + // Rendering a visible tree. + if (prevState !== null) { + // We're going from hidden -> visible. + var _prevCachePool = null; + + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + _prevCachePool = prevState.cachePool; } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - mountHookTypesDev(); - return mountDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - mountHookTypesDev(); - return mountTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - mountHookTypesDev(); - return mountMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - mountHookTypesDev(); - return mountId(); + + var transitions = null; + + if (enableTransitionTracing) { + // We have now gone from hidden to visible, so any transitions should + // be added to the stack to get added to any Offscreen/suspense children + var instance = workInProgress.stateNode; + + if (instance !== null && instance._transitions != null) { + transitions = Array.from(instance._transitions); + } + } + + pushTransition(workInProgress, _prevCachePool, transitions); // Push the lanes that were skipped when we bailed out. + + pushHiddenContext(workInProgress, prevState); + reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state + + workInProgress.memoizedState = null; + } else { + // We weren't previously hidden, and we still aren't, so there's nothing + // special to do. Need to push to the stack regardless, though, to avoid + // a push/pop misalignment. + { + // If the render that spawned this one accessed the cache pool, resume + // using the same cache. Unless the parent changed, since that means + // there was a refresh. + if (current !== null) { + pushTransition(workInProgress, null, null); + } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. + + reuseHiddenContextOnStack(workInProgress); + reuseSuspenseHandlerOnStack(workInProgress); } + } + + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} + +function deferHiddenOffscreenComponent( + current, + workInProgress, + nextBaseLanes, + renderLanes +) { + var nextState = { + baseLanes: nextBaseLanes, + // Save the cache pool so we can resume later. + cachePool: getOffscreenDeferredCache() }; + workInProgress.memoizedState = nextState; { - HooksDispatcherOnMountInDEV.useCacheRefresh = function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; - } + // push the cache pool even though we're going to bail out + // because otherwise there'd be a context mismatch + if (current !== null) { + pushTransition(workInProgress, null, null); + } + } // We're about to bail out, but we need to push this to the stack anyway + // to avoid a push/pop misalignment. - { - HooksDispatcherOnMountInDEV.use = use; - } + reuseHiddenContextOnStack(workInProgress); + pushOffscreenSuspenseHandler(workInProgress); - { - HooksDispatcherOnMountInDEV.useMemoCache = useMemoCache; + if (enableLazyContextPropagation && current !== null) { + // Since this tree will resume rendering in a separate render, we need + // to propagate parent contexts now so we don't lose track of which + // ones changed. + propagateParentContextChangesToDeferredTree( + current, + workInProgress, + renderLanes + ); } - { - HooksDispatcherOnMountInDEV.useEffectEvent = function useEffectEvent( - callback - ) { - currentHookNameInDev = "useEffectEvent"; - mountHookTypesDev(); - return mountEvent(callback); + return null; +} // Note: These happen to have identical begin phases, for now. We shouldn't hold +// ourselves to this constraint, though. If the behavior diverges, we should +// fork the function. + +var updateLegacyHiddenComponent = updateOffscreenComponent; + +function updateCacheComponent(current, workInProgress, renderLanes) { + prepareToReadContext(workInProgress, renderLanes); + var parentCache = readContext(CacheContext); + + if (current === null) { + // Initial mount. Request a fresh cache from the pool. + var freshCache = requestCacheFromPool(renderLanes); + var initialState = { + parent: parentCache, + cache: freshCache }; - } + workInProgress.memoizedState = initialState; + initializeUpdateQueue(workInProgress); + pushCacheProvider(workInProgress, freshCache); + } else { + // Check for updates + if (includesSomeLane(current.lanes, renderLanes)) { + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, null, null, renderLanes); + } - HooksDispatcherOnMountWithHookTypesInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - updateHookTypesDev(); - return mountCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - updateHookTypesDev(); - return mountEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - updateHookTypesDev(); - return mountImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - updateHookTypesDev(); - return mountInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - updateHookTypesDev(); - return mountLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + var prevState = current.memoizedState; + var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was + // a refresh. - try { - return mountMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + if (prevState.parent !== parentCache) { + // Refresh in parent. Update the parent. + var derivedState = { + parent: parentCache, + cache: parentCache + }; // Copied from getDerivedStateFromProps implementation. Once the update + // queue is empty, persist the derived state onto the base state. - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + workInProgress.memoizedState = derivedState; + + if (workInProgress.lanes === NoLanes) { + var updateQueue = workInProgress.updateQueue; + workInProgress.memoizedState = updateQueue.baseState = derivedState; } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; - try { - return mountState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent + // already did. + } else { + // The parent didn't refresh. Now check if this cache did. + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); + + if (nextCache !== prevState.cache) { + // This cache refreshed. Propagate a context change. + propagateContextChange(workInProgress, CacheContext, renderLanes); } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return mountDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return mountTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - updateHookTypesDev(); - return mountMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return mountId(); } - }; - - { - HooksDispatcherOnMountWithHookTypesInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return mountRefresh(); - }; } - { - HooksDispatcherOnMountWithHookTypesInDEV.use = use; - } + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} // This should only be called if the name changes - { - HooksDispatcherOnMountWithHookTypesInDEV.useMemoCache = useMemoCache; - } +function updateTracingMarkerComponent(current, workInProgress, renderLanes) { + if (!enableTransitionTracing) { + return null; + } // TODO: (luna) Only update the tracing marker if it's newly rendered or it's name changed. + // A tracing marker is only associated with the transitions that rendered + // or updated it, so we can create a new set of transitions each time - { - HooksDispatcherOnMountWithHookTypesInDEV.useEffectEvent = - function useEffectEvent(callback) { - currentHookNameInDev = "useEffectEvent"; - updateHookTypesDev(); - return mountEvent(callback); + if (current === null) { + var currentTransitions = getPendingTransitions(); + + if (currentTransitions !== null) { + var markerInstance = { + tag: TransitionTracingMarker, + transitions: new Set(currentTransitions), + pendingBoundaries: null, + name: workInProgress.pendingProps.name, + aborts: null }; + workInProgress.stateNode = markerInstance; // We call the marker complete callback when all child suspense boundaries resolve. + // We do this in the commit phase on Offscreen. If the marker has no child suspense + // boundaries, we need to schedule a passive effect to make sure we call the marker + // complete callback. + + workInProgress.flags |= Passive$1; + } + } else { + { + if (current.memoizedProps.name !== workInProgress.pendingProps.name) { + error( + "Changing the name of a tracing marker after mount is not supported. " + + "To remount the tracing marker, pass it a new key." + ); + } + } } - HooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - updateHookTypesDev(); - return updateLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + var instance = workInProgress.stateNode; - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + if (instance !== null) { + pushMarkerInstance(workInProgress, instance); + } - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - try { - return updateState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return updateDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return updateTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); - } - }; +function updateFragment(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - { - HooksDispatcherOnUpdateInDEV.useCacheRefresh = function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; - } +function updateMode(current, workInProgress, renderLanes) { + var nextChildren = workInProgress.pendingProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} +function updateProfiler(current, workInProgress, renderLanes) { { - HooksDispatcherOnUpdateInDEV.use = use; - } + workInProgress.flags |= Update; - { - HooksDispatcherOnUpdateInDEV.useMemoCache = useMemoCache; + { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + var stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } } - { - HooksDispatcherOnUpdateInDEV.useEffectEvent = function useEffectEvent( - callback - ) { - currentHookNameInDev = "useEffectEvent"; - updateHookTypesDev(); - return updateEvent(callback); - }; - } + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - HooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - updateHookTypesDev(); - return updateLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnRerenderInDEV; +function markRef$1(current, workInProgress) { + var ref = workInProgress.ref; - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnRerenderInDEV; + if ( + (current === null && ref !== null) || + (current !== null && current.ref !== ref) + ) { + // Schedule a Ref effect + workInProgress.flags |= Ref; + workInProgress.flags |= RefStatic; + } +} - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnRerenderInDEV; +function updateFunctionComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes +) { + { + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; - try { - return rerenderState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(Component) + ); } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - updateHookTypesDev(); - return rerenderDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - updateHookTypesDev(); - return rerenderTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - updateHookTypesDev(); - return updateId(); } - }; + } + + var context; { - HooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + context = getMaskedContext(workInProgress, unmaskedContext); } - { - HooksDispatcherOnRerenderInDEV.use = use; + var nextChildren; + var hasId; + prepareToReadContext(workInProgress, renderLanes); + + if (enableSchedulingProfiler) { + markComponentRenderStarted(workInProgress); } { - HooksDispatcherOnRerenderInDEV.useMemoCache = useMemoCache; + ReactCurrentOwner$2.current = workInProgress; + setIsRendering(true); + nextChildren = renderWithHooks( + current, + workInProgress, + Component, + nextProps, + context, + renderLanes + ); + hasId = checkDidRenderIdHook(); + setIsRendering(false); } - { - HooksDispatcherOnRerenderInDEV.useEffectEvent = function useEffectEvent( - callback - ) { - currentHookNameInDev = "useEffectEvent"; - updateHookTypesDev(); - return updateEvent(callback); - }; + if (enableSchedulingProfiler) { + markComponentRenderStopped(); } - InvalidNestedHooksDispatcherOnMountInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } - try { - return mountMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + if (getIsHydrating() && hasId) { + pushMaterializedTreeId(workInProgress); + } // React DevTools reads this flag. - try { - return mountReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountRef(initialValue); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - mountHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnMountInDEV; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - try { - return mountState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountId(); - } - }; +function replayFunctionComponent( + current, + workInProgress, + nextProps, + Component, + renderLanes +) { + // This function is used to replay a component that previously suspended, + // after its data resolves. It's a simplified version of + // updateFunctionComponent that reuses the hooks from the previous attempt. + var context; { - InvalidNestedHooksDispatcherOnMountInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - mountHookTypesDev(); - return mountRefresh(); - }; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); + context = getMaskedContext(workInProgress, unmaskedContext); } - { - InvalidNestedHooksDispatcherOnMountInDEV.use = function (usable) { - warnInvalidHookAccess(); - return use(usable); - }; + prepareToReadContext(workInProgress, renderLanes); + + if (enableSchedulingProfiler) { + markComponentRenderStarted(workInProgress); } - { - InvalidNestedHooksDispatcherOnMountInDEV.useMemoCache = function (size) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + var nextChildren = replaySuspendedComponentWithHooks( + current, + workInProgress, + Component, + nextProps, + context + ); + var hasId = checkDidRenderIdHook(); + + if (enableSchedulingProfiler) { + markComponentRenderStopped(); } - { - InvalidNestedHooksDispatcherOnMountInDEV.useEffectEvent = - function useEffectEvent(callback) { - currentHookNameInDev = "useEffectEvent"; - warnInvalidHookAccess(); - mountHookTypesDev(); - return mountEvent(callback); - }; + if (current !== null && !didReceiveUpdate) { + bailoutHooks(current, workInProgress, renderLanes); + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } - InvalidNestedHooksDispatcherOnUpdateInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + if (getIsHydrating() && hasId) { + pushMaterializedTreeId(workInProgress); + } // React DevTools reads this flag. - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} + +function updateClassComponent( + current, + workInProgress, + Component, + nextProps, + renderLanes +) { + { + // This is used by DevTools to force a boundary to error. + switch (shouldError(workInProgress)) { + case false: { + var _instance = workInProgress.stateNode; + var ctor = workInProgress.type; // TODO This way of resetting the error boundary state is a hack. + // Is there a better way to do this? + + var tempInstance = new ctor( + workInProgress.memoizedProps, + _instance.context + ); + var state = tempInstance.state; + + _instance.updater.enqueueSetState(_instance, state, null); + + break; } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; - try { - return updateReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + case true: { + workInProgress.flags |= DidCapture; + workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes + + var error$1 = new Error("Simulated error coming from DevTools"); + var lane = pickArbitraryLane(renderLanes); + workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); // Schedule the error boundary to re-render using updated state + + var update = createClassErrorUpdate( + workInProgress, + createCapturedValueAtFiber(error$1, workInProgress), + lane + ); + enqueueCapturedUpdate(workInProgress, update); + break; } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + } - try { - return updateState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + if (workInProgress.type !== workInProgress.elementType) { + // Lazy component props can't be validated in createElement + // because they're only guaranteed to be resolved here. + var innerPropTypes = Component.propTypes; + + if (innerPropTypes) { + checkPropTypes( + innerPropTypes, + nextProps, // Resolved props + "prop", + getComponentNameFromType(Component) + ); } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); } - }; + } // 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. - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; - } + var hasContext; - { - InvalidNestedHooksDispatcherOnUpdateInDEV.use = function (usable) { - warnInvalidHookAccess(); - return use(usable); - }; + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; } - { - InvalidNestedHooksDispatcherOnUpdateInDEV.useMemoCache = function (size) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + prepareToReadContext(workInProgress, renderLanes); + var instance = workInProgress.stateNode; + var shouldUpdate; + + if (instance === null) { + resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress); // In the initial pass we might need to construct the instance. + + constructClassInstance(workInProgress, Component, nextProps); + mountClassInstance(workInProgress, Component, nextProps, renderLanes); + shouldUpdate = true; + } else if (current === null) { + // In a resume, we'll already have an instance we can reuse. + shouldUpdate = resumeMountClassInstance( + workInProgress, + Component, + nextProps, + renderLanes + ); + } else { + shouldUpdate = updateClassInstance( + current, + workInProgress, + Component, + nextProps, + renderLanes + ); } + var nextUnitOfWork = finishClassComponent( + current, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderLanes + ); + { - InvalidNestedHooksDispatcherOnUpdateInDEV.useEffectEvent = - function useEffectEvent(callback) { - currentHookNameInDev = "useEffectEvent"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEvent(callback); - }; + var inst = workInProgress.stateNode; + + if (shouldUpdate && inst.props !== nextProps) { + if (!didWarnAboutReassigningProps) { + error( + "It looks like %s is reassigning its own `this.props` while rendering. " + + "This is not supported and can lead to confusing bugs.", + getComponentNameFromFiber(workInProgress) || "a component" + ); + } + + didWarnAboutReassigningProps = true; + } } - InvalidNestedHooksDispatcherOnRerenderInDEV = { - readContext: function (context) { - warnInvalidContextAccess(); - return readContext(context); - }, - useCallback: function (callback, deps) { - currentHookNameInDev = "useCallback"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateCallback(callback, deps); - }, - useContext: function (context) { - currentHookNameInDev = "useContext"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return readContext(context); - }, - useEffect: function (create, deps) { - currentHookNameInDev = "useEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEffect(create, deps); - }, - useImperativeHandle: function (ref, create, deps) { - currentHookNameInDev = "useImperativeHandle"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateImperativeHandle(ref, create, deps); - }, - useInsertionEffect: function (create, deps) { - currentHookNameInDev = "useInsertionEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateInsertionEffect(create, deps); - }, - useLayoutEffect: function (create, deps) { - currentHookNameInDev = "useLayoutEffect"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateLayoutEffect(create, deps); - }, - useMemo: function (create, deps) { - currentHookNameInDev = "useMemo"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; + return nextUnitOfWork; +} - try { - return updateMemo(create, deps); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; - } - }, - useReducer: function (reducer, initialArg, init) { - currentHookNameInDev = "useReducer"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; +function finishClassComponent( + current, + workInProgress, + Component, + shouldUpdate, + hasContext, + renderLanes +) { + // Refs should update even if shouldComponentUpdate returns false + markRef$1(current, workInProgress); + var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; - try { - return rerenderReducer(reducer, initialArg, init); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + if (!shouldUpdate && !didCaptureError) { + // Context providers should defer to sCU for rendering + if (hasContext) { + invalidateContextProvider(workInProgress, Component, false); + } + + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } + + var instance = workInProgress.stateNode; // Rerender + + ReactCurrentOwner$2.current = workInProgress; + var nextChildren; + + if ( + didCaptureError && + typeof Component.getDerivedStateFromError !== "function" + ) { + // If we captured an error, but getDerivedStateFromError 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; + + { + stopProfilerTimerIfRunning(); + } + } else { + if (enableSchedulingProfiler) { + markComponentRenderStarted(workInProgress); + } + + { + setIsRendering(true); + nextChildren = instance.render(); + + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); + + try { + instance.render(); + } finally { + setIsStrictModeForDevtools(false); + } } - }, - useRef: function (initialValue) { - currentHookNameInDev = "useRef"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateRef(); - }, - useState: function (initialState) { - currentHookNameInDev = "useState"; - warnInvalidHookAccess(); - updateHookTypesDev(); - var prevDispatcher = ReactCurrentDispatcher$1.current; - ReactCurrentDispatcher$1.current = - InvalidNestedHooksDispatcherOnUpdateInDEV; - try { - return rerenderState(initialState); - } finally { - ReactCurrentDispatcher$1.current = prevDispatcher; + setIsRendering(false); + } + + if (enableSchedulingProfiler) { + markComponentRenderStopped(); + } + } // React DevTools reads this flag. + + workInProgress.flags |= PerformedWork; + + if (current !== 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, + workInProgress, + nextChildren, + renderLanes + ); + } else { + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } // 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, workInProgress, renderLanes) { + pushHostRootContext(workInProgress); + + if (current === null) { + throw new Error("Should have a current fiber. This is a bug in React."); + } + + var nextProps = workInProgress.pendingProps; + var prevState = workInProgress.memoizedState; + var prevChildren = prevState.element; + cloneUpdateQueue(current, workInProgress); + processUpdateQueue(workInProgress, nextProps, null, renderLanes); + var nextState = workInProgress.memoizedState; + var root = workInProgress.stateNode; + pushRootTransition(workInProgress); + + if (enableTransitionTracing) { + pushRootMarkerInstance(workInProgress); + } + + { + var nextCache = nextState.cache; + pushCacheProvider(workInProgress, nextCache); + + if (nextCache !== prevState.cache) { + // The root cache refreshed. + propagateContextChange(workInProgress, CacheContext, renderLanes); + } + } // Caution: React DevTools currently depends on this property + // being called "element". + + var nextChildren = nextState.element; + + if (prevState.isDehydrated) { + // This is a hydration root whose shell has not yet hydrated. We should + // attempt to hydrate. + // Flip isDehydrated to false to indicate that when this render + // finishes, the root will no longer be dehydrated. + var overrideState = { + element: nextChildren, + isDehydrated: false, + cache: nextState.cache + }; + var updateQueue = workInProgress.updateQueue; // `baseState` can always be the last state because the root doesn't + // have reducer functions so it doesn't need rebasing. + + updateQueue.baseState = overrideState; + workInProgress.memoizedState = overrideState; + + if (workInProgress.flags & ForceClientRender) { + // Something errored during a previous attempt to hydrate the shell, so we + // forced a client render. + var recoverableError = createCapturedValueAtFiber( + new Error( + "There was an error while hydrating. Because the error happened outside " + + "of a Suspense boundary, the entire root will switch to " + + "client rendering." + ), + workInProgress + ); + return mountHostRootWithoutHydrating( + current, + workInProgress, + nextChildren, + renderLanes, + recoverableError + ); + } else if (nextChildren !== prevChildren) { + var _recoverableError = createCapturedValueAtFiber( + new Error( + "This root received an early update, before anything was able " + + "hydrate. Switched the entire root to client rendering." + ), + workInProgress + ); + + return mountHostRootWithoutHydrating( + current, + workInProgress, + nextChildren, + renderLanes, + _recoverableError + ); + } else { + // The outermost shell has not hydrated yet. Start hydrating. + enterHydrationState(workInProgress); + + { + var mutableSourceEagerHydrationData = + root.mutableSourceEagerHydrationData; + + if (mutableSourceEagerHydrationData != null) { + for (var i = 0; i < mutableSourceEagerHydrationData.length; i += 2) { + var mutableSource = mutableSourceEagerHydrationData[i]; + var version = mutableSourceEagerHydrationData[i + 1]; + setWorkInProgressVersion(mutableSource, version); + } + } + } + + var child = mountChildFibers( + workInProgress, + null, + nextChildren, + renderLanes + ); + workInProgress.child = child; + var node = child; + + while (node) { + // Mark each child as hydrating. This is a fast path to know whether this + // tree is part of a hydrating tree. This is used to determine if a child + // node has fully mounted yet, and for scheduling event replaying. + // Conceptually this is similar to Placement in that a new subtree is + // inserted into the React tree here. It just happens to not need DOM + // mutations because it already exists. + node.flags = (node.flags & ~Placement) | Hydrating; + node = node.sibling; } - }, - useDebugValue: function (value, formatterFn) { - currentHookNameInDev = "useDebugValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateDebugValue(); - }, - useDeferredValue: function (value) { - currentHookNameInDev = "useDeferredValue"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderDeferredValue(value); - }, - useTransition: function () { - currentHookNameInDev = "useTransition"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return rerenderTransition(); - }, - useMutableSource: function (source, getSnapshot, subscribe) { - currentHookNameInDev = "useMutableSource"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateMutableSource(source, getSnapshot, subscribe); - }, - useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) { - currentHookNameInDev = "useSyncExternalStore"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateSyncExternalStore(subscribe, getSnapshot); - }, - useId: function () { - currentHookNameInDev = "useId"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateId(); } - }; + } else { + // Root is not dehydrated. Either this is a client-only root, or it + // already hydrated. + resetHydrationState(); + + if (nextChildren === prevChildren) { + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } + + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } + + return workInProgress.child; +} + +function mountHostRootWithoutHydrating( + current, + workInProgress, + nextChildren, + renderLanes, + recoverableError +) { + // Revert to client rendering. + resetHydrationState(); + queueHydrationError(recoverableError); + workInProgress.flags |= ForceClientRender; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} + +function updateHostComponent$1(current, workInProgress, renderLanes) { + pushHostContext(workInProgress); + + if (current === null) { + tryToClaimNextHydratableInstance(workInProgress); + } + + var type = workInProgress.type; + var nextProps = workInProgress.pendingProps; + var prevProps = current !== null ? current.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 has 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.flags |= ContentReset; + } + + markRef$1(current, workInProgress); + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} + +function updateHostHoistable(current, workInProgress, renderLanes) { + markRef$1(current, workInProgress); + var currentProps = current === null ? null : current.memoizedProps; + var resource = (workInProgress.memoizedState = getResource( + workInProgress.type, + currentProps, + workInProgress.pendingProps + )); + + if (current === null) { + if (!getIsHydrating() && resource === null) { + // This is not a Resource Hoistable and we aren't hydrating so we construct the instance. + workInProgress.stateNode = createHoistableInstance( + workInProgress.type, + workInProgress.pendingProps, + getRootHostContainer(), + workInProgress + ); + } + } // Resources never have reconciler managed children. It is possible for + // the host implementation of getResource to consider children in the + // resource construction but they will otherwise be discarded. In practice + // this precludes all but the simplest children and Host specific warnings + // should be implemented to warn when children are passsed when otherwise not + // expected + + return null; +} + +function updateHostSingleton(current, workInProgress, renderLanes) { + pushHostContext(workInProgress); + + if (current === null) { + claimHydratableSingleton(workInProgress); + } + + var nextChildren = workInProgress.pendingProps.children; + + if (current === null && !getIsHydrating()) { + // Similar to Portals we append Singleton children in the commit phase. So we + // Track insertions even on mount. + // TODO: Consider unifying this with how the root works. + workInProgress.child = reconcileChildFibers( + workInProgress, + null, + nextChildren, + renderLanes + ); + } else { + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } + + markRef$1(current, workInProgress); + return workInProgress.child; +} + +function updateHostText$1(current, workInProgress) { + if (current === null) { + tryToClaimNextHydratableTextInstance(workInProgress); + } // Nothing to do here. This is terminal. We'll do the completion step + // immediately after. + + return null; +} + +function mountLazyComponent( + _current, + workInProgress, + elementType, + renderLanes +) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); + var props = workInProgress.pendingProps; + var lazyComponent = elementType; + var payload = lazyComponent._payload; + var init = lazyComponent._init; + var Component = init(payload); // Store the unwrapped component in the type. + + workInProgress.type = Component; + var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); + var resolvedProps = resolveDefaultProps(Component, props); + var child; + + switch (resolvedTag) { + case FunctionComponent: { + { + validateFunctionComponentInDev(workInProgress, Component); + workInProgress.type = Component = + resolveFunctionForHotReloading(Component); + } + + child = updateFunctionComponent( + null, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + return child; + } + + case ClassComponent: { + { + workInProgress.type = Component = + resolveClassForHotReloading(Component); + } + + child = updateClassComponent( + null, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + return child; + } + + case ForwardRef: { + { + workInProgress.type = Component = + resolveForwardRefForHotReloading(Component); + } + + child = updateForwardRef( + null, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + return child; + } + + case MemoComponent: { + { + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = Component.propTypes; + + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + resolvedProps, // Resolved for outer only + "prop", + getComponentNameFromType(Component) + ); + } + } + } + + child = updateMemoComponent( + null, + workInProgress, + Component, + resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too + renderLanes + ); + return child; + } + } + + var hint = ""; + + { + if ( + Component !== null && + typeof Component === "object" && + Component.$$typeof === REACT_LAZY_TYPE + ) { + hint = " Did you wrap a component in React.lazy() more than once?"; + } + } // This message intentionally doesn't mention ForwardRef or MemoComponent + // because the fact that it's a separate type of work is an + // implementation detail. + + throw new Error( + "Element type is invalid. Received a promise that resolves to: " + + Component + + ". " + + ("Lazy element type must resolve to a class or function." + hint) + ); +} + +function mountIncompleteClassComponent( + _current, + workInProgress, + Component, + nextProps, + renderLanes +) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // 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; + + if (isContextProvider(Component)) { + hasContext = true; + pushContextProvider(workInProgress); + } else { + hasContext = false; + } + + prepareToReadContext(workInProgress, renderLanes); + constructClassInstance(workInProgress, Component, nextProps); + mountClassInstance(workInProgress, Component, nextProps, renderLanes); + return finishClassComponent( + null, + workInProgress, + Component, + true, + hasContext, + renderLanes + ); +} + +function mountIndeterminateComponent( + _current, + workInProgress, + Component, + renderLanes +) { + resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); + var props = workInProgress.pendingProps; + var context; { - InvalidNestedHooksDispatcherOnRerenderInDEV.useCacheRefresh = - function useCacheRefresh() { - currentHookNameInDev = "useCacheRefresh"; - updateHookTypesDev(); - return updateRefresh(); - }; + var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); + context = getMaskedContext(workInProgress, unmaskedContext); } - { - InvalidNestedHooksDispatcherOnRerenderInDEV.use = function (usable) { - warnInvalidHookAccess(); - return use(usable); - }; - } + prepareToReadContext(workInProgress, renderLanes); + var value; + var hasId; - { - InvalidNestedHooksDispatcherOnRerenderInDEV.useMemoCache = function (size) { - warnInvalidHookAccess(); - return useMemoCache(size); - }; + if (enableSchedulingProfiler) { + markComponentRenderStarted(workInProgress); } { - InvalidNestedHooksDispatcherOnRerenderInDEV.useEffectEvent = - function useEffectEvent(callback) { - currentHookNameInDev = "useEffectEvent"; - warnInvalidHookAccess(); - updateHookTypesDev(); - return updateEvent(callback); - }; - } -} + if ( + Component.prototype && + typeof Component.prototype.render === "function" + ) { + var componentName = getComponentNameFromType(Component) || "Unknown"; -var now = Scheduler.unstable_now; -var commitTime = 0; -var layoutEffectStartTime = -1; -var profilerStartTime = -1; -var passiveEffectStartTime = -1; -/** - * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect). - * - * The overall sequence is: - * 1. render - * 2. commit (and call `onRender`, `onCommit`) - * 3. check for nested updates - * 4. flush passive effects (and call `onPostCommit`) - * - * Nested updates are identified in step 3 above, - * but step 4 still applies to the work that was just committed. - * We use two flags to track nested updates then: - * one tracks whether the upcoming update is a nested update, - * and the other tracks whether the current update was a nested update. - * The first value gets synced to the second at the start of the render phase. - */ + if (!didWarnAboutBadClass[componentName]) { + error( + "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + + "This is likely to cause errors. Change %s to extend React.Component instead.", + componentName, + componentName + ); -var currentUpdateIsNested = false; -var nestedUpdateScheduled = false; + didWarnAboutBadClass[componentName] = true; + } + } -function isCurrentUpdateNested() { - return currentUpdateIsNested; -} + if (workInProgress.mode & StrictLegacyMode) { + ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); + } -function markNestedUpdateScheduled() { - { - nestedUpdateScheduled = true; + setIsRendering(true); + ReactCurrentOwner$2.current = workInProgress; + value = renderWithHooks( + null, + workInProgress, + Component, + props, + context, + renderLanes + ); + hasId = checkDidRenderIdHook(); + setIsRendering(false); } -} -function resetNestedUpdateFlag() { + if (enableSchedulingProfiler) { + markComponentRenderStopped(); + } // React DevTools reads this flag. + + workInProgress.flags |= PerformedWork; + { - currentUpdateIsNested = false; - nestedUpdateScheduled = false; + // Support for module components is deprecated and is removed behind a flag. + // Whether or not it would crash later, we want to show a good message in DEV first. + if ( + typeof value === "object" && + value !== null && + typeof value.render === "function" && + value.$$typeof === undefined + ) { + var _componentName = getComponentNameFromType(Component) || "Unknown"; + + if (!didWarnAboutModulePatternComponent[_componentName]) { + error( + "The <%s /> component appears to be a function component that returns a class instance. " + + "Change %s to a class that extends React.Component instead. " + + "If you can't use a class try assigning the prototype on the function as a workaround. " + + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + + "cannot be called with `new` by React.", + _componentName, + _componentName, + _componentName + ); + + didWarnAboutModulePatternComponent[_componentName] = true; + } + } } -} -function syncNestedUpdateFlag() { { - currentUpdateIsNested = nestedUpdateScheduled; - nestedUpdateScheduled = false; - } -} + // Proceed under the assumption that this is a function component + workInProgress.tag = FunctionComponent; -function getCommitTime() { - return commitTime; -} + if (getIsHydrating() && hasId) { + pushMaterializedTreeId(workInProgress); + } -function recordCommitTime() { - commitTime = now(); -} + reconcileChildren(null, workInProgress, value, renderLanes); -function startProfilerTimer(fiber) { - profilerStartTime = now(); + { + validateFunctionComponentInDev(workInProgress, Component); + } - if (fiber.actualStartTime < 0) { - fiber.actualStartTime = now(); + return workInProgress.child; } } -function stopProfilerTimerIfRunning(fiber) { - profilerStartTime = -1; -} +function validateFunctionComponentInDev(workInProgress, Component) { + { + if (Component) { + if (Component.childContextTypes) { + error( + "%s(...): childContextTypes cannot be defined on a function component.", + Component.displayName || Component.name || "Component" + ); + } + } -function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { - if (profilerStartTime >= 0) { - var elapsedTime = now() - profilerStartTime; - fiber.actualDuration += elapsedTime; + if (workInProgress.ref !== null) { + var info = ""; + var ownerName = getCurrentFiberOwnerNameInDevOrNull(); - if (overrideBaseTime) { - fiber.selfBaseDuration = elapsedTime; + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + + var warningKey = ownerName || ""; + var debugSource = workInProgress._debugSource; + + if (debugSource) { + warningKey = debugSource.fileName + ":" + debugSource.lineNumber; + } + + if (!didWarnAboutFunctionRefs[warningKey]) { + didWarnAboutFunctionRefs[warningKey] = true; + + error( + "Function components cannot be given refs. " + + "Attempts to access this ref will fail. " + + "Did you mean to use React.forwardRef()?%s", + info + ); + } } - profilerStartTime = -1; - } -} + if (Component.defaultProps !== undefined) { + var componentName = getComponentNameFromType(Component) || "Unknown"; -function recordLayoutEffectDuration(fiber) { - if (layoutEffectStartTime >= 0) { - var elapsedTime = now() - layoutEffectStartTime; - layoutEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor - // Or the root (for the DevTools Profiler to read) + if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { + error( + "%s: Support for defaultProps will be removed from function components " + + "in a future major release. Use JavaScript default parameters instead.", + componentName + ); - var parentFiber = fiber.return; + didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + } + } - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.effectDuration += elapsedTime; - return; + if (typeof Component.getDerivedStateFromProps === "function") { + var _componentName3 = getComponentNameFromType(Component) || "Unknown"; - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += elapsedTime; - return; + if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) { + error( + "%s: Function components do not support getDerivedStateFromProps.", + _componentName3 + ); + + didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true; } + } - parentFiber = parentFiber.return; + if ( + typeof Component.contextType === "object" && + Component.contextType !== null + ) { + var _componentName4 = getComponentNameFromType(Component) || "Unknown"; + + if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { + error( + "%s: Function components do not support contextType.", + _componentName4 + ); + + didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; + } } } } -function recordPassiveEffectDuration(fiber) { - if (passiveEffectStartTime >= 0) { - var elapsedTime = now() - passiveEffectStartTime; - passiveEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor - // Or the root (for the DevTools Profiler to read) +var SUSPENDED_MARKER = { + dehydrated: null, + treeContext: null, + retryLane: NoLane +}; - var parentFiber = fiber.return; +function mountSuspenseOffscreenState(renderLanes) { + return { + baseLanes: renderLanes, + cachePool: getSuspendedCache() + }; +} - while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; +function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { + var cachePool = null; - if (root !== null) { - root.passiveEffectDuration += elapsedTime; - } + { + var prevCachePool = prevOffscreenState.cachePool; - return; + if (prevCachePool !== null) { + var parentCache = CacheContext._currentValue; - case Profiler: - var parentStateNode = parentFiber.stateNode; + if (prevCachePool.parent !== parentCache) { + // Detected a refresh in the parent. This overrides any previously + // suspended cache. + cachePool = { + parent: parentCache, + pool: parentCache + }; + } else { + // We can reuse the cache from last time. The only thing that would have + // overridden it is a parent refresh, which we checked for above. + cachePool = prevCachePool; + } + } else { + // If there's no previous cache pool, grab the current one. + cachePool = getSuspendedCache(); + } + } - if (parentStateNode !== null) { - // Detached fibers have their state node cleared out. - // In this case, the return pointer is also cleared out, - // so we won't be able to report the time spent in this Profiler's subtree. - parentStateNode.passiveEffectDuration += elapsedTime; - } + return { + baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), + cachePool: cachePool + }; +} // TODO: Probably should inline this back - return; - } +function shouldRemainOnFallback(current, workInProgress, renderLanes) { + // If we're already showing a fallback, there are cases where we need to + // remain on that fallback regardless of whether the content has resolved. + // For example, SuspenseList coordinates when nested content appears. + if (current !== null) { + var suspenseState = current.memoizedState; - parentFiber = parentFiber.return; + if (suspenseState === null) { + // Currently showing content. Don't hide it, even if ForceSuspenseFallback + // is true. More precise name might be "ForceRemainSuspenseFallback". + // Note: This is a factoring smell. Can't remain on a fallback if there's + // no fallback to remain on. + return false; } - } -} + } // Not currently showing content. Consult the Suspense context. -function startLayoutEffectTimer() { - layoutEffectStartTime = now(); + var suspenseContext = suspenseStackCursor.current; + return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); } -function startPassiveEffectTimer() { - passiveEffectStartTime = now(); +function getRemainingWorkInPrimaryTree(current, renderLanes) { + // TODO: Should not remove render lanes that were pinged during this render + return removeLanes(current.childLanes, renderLanes); } -function transferActualDuration(fiber) { - // Transfer time spent rendering these children so we don't lose it - // after we rerender. This is used as a helper in special cases - // where we should count the work of multiple passes. - var child = fiber.child; +function updateSuspenseComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. - while (child) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - fiber.actualDuration += child.actualDuration; - child = child.sibling; + { + if (shouldSuspend(workInProgress)) { + workInProgress.flags |= DidCapture; + } } -} -function resolveDefaultProps(Component, baseProps) { - if (Component && Component.defaultProps) { - // Resolve default props. Taken from ReactElement - var props = assign({}, baseProps); - var defaultProps = Component.defaultProps; + var showFallback = false; + var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; - for (var propName in defaultProps) { - if (props[propName] === undefined) { - props[propName] = defaultProps[propName]; + if (didSuspend || shouldRemainOnFallback(current)) { + // Something in this boundary's subtree already suspended. Switch to + // rendering the fallback children. + showFallback = true; + workInProgress.flags &= ~DidCapture; + } // OK, the next part is confusing. We're about to reconcile the Suspense + // boundary's children. This involves some custom reconciliation logic. Two + // main reasons this is so complicated. + // + // First, Legacy Mode has different semantics for backwards compatibility. The + // primary tree will commit in an inconsistent state, so when we do the + // second pass to render the fallback, we do some exceedingly, uh, clever + // hacks to make that not totally break. Like transferring effects and + // deletions from hidden tree. In Concurrent Mode, it's much simpler, + // because we bailout on the primary tree completely and leave it in its old + // state, no effects. Same as what we do for Offscreen (except that + // Offscreen doesn't have the first render pass). + // + // Second is hydration. During hydration, the Suspense fiber has a slightly + // different layout, where the child points to a dehydrated fragment, which + // contains the DOM rendered by the server. + // + // Third, even if you set all that aside, Suspense is like error boundaries in + // that we first we try to render one tree, and if that fails, we render again + // and switch to a different tree. Like a try/catch block. So we have to track + // which branch we're currently rendering. Ideally we would model this using + // a stack. + + if (current === null) { + // Initial mount + // Special path for hydration + // If we're currently hydrating, try to hydrate this boundary. + if (getIsHydrating()) { + // We must push the suspense handler context *before* attempting to + // hydrate, to avoid a mismatch in case it errors. + if (showFallback) { + pushPrimaryTreeSuspenseHandler(workInProgress); + } else { + pushFallbackTreeSuspenseHandler(workInProgress); } + + tryToClaimNextHydratableSuspenseInstance(workInProgress); // This could've been a dehydrated suspense component. + + var suspenseState = workInProgress.memoizedState; + + if (suspenseState !== null) { + var dehydrated = suspenseState.dehydrated; + + if (dehydrated !== null) { + return mountDehydratedSuspenseComponent(workInProgress, dehydrated); + } + } // If hydration didn't succeed, fall through to the normal Suspense path. + // To avoid a stack mismatch we need to pop the Suspense handler that we + // pushed above. This will become less awkward when move the hydration + // logic to its own fiber. + + popSuspenseHandler(workInProgress); } - return props; - } + var nextPrimaryChildren = nextProps.children; + var nextFallbackChildren = nextProps.fallback; - return baseProps; -} + if (showFallback) { + pushFallbackTreeSuspenseHandler(workInProgress); + var fallbackFragment = mountSuspenseFallbackChildren( + workInProgress, + nextPrimaryChildren, + nextFallbackChildren, + renderLanes + ); + var primaryChildFragment = workInProgress.child; + primaryChildFragment.memoizedState = + mountSuspenseOffscreenState(renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; -var fakeInternalInstance = {}; -var didWarnAboutStateAssignmentForComponent; -var didWarnAboutUninitializedState; -var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate; -var didWarnAboutLegacyLifecyclesAndDerivedState; -var didWarnAboutUndefinedDerivedState; -var didWarnAboutDirectlyAssigningPropsToState; -var didWarnAboutContextTypeAndContextTypes; -var didWarnAboutInvalidateContextType; -var didWarnOnInvalidCallback; + if (enableTransitionTracing) { + var currentTransitions = getPendingTransitions(); -{ - didWarnAboutStateAssignmentForComponent = new Set(); - didWarnAboutUninitializedState = new Set(); - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set(); - didWarnAboutLegacyLifecyclesAndDerivedState = new Set(); - didWarnAboutDirectlyAssigningPropsToState = new Set(); - didWarnAboutUndefinedDerivedState = new Set(); - didWarnAboutContextTypeAndContextTypes = new Set(); - didWarnAboutInvalidateContextType = new Set(); - didWarnOnInvalidCallback = new Set(); // This is so gross but it's at least non-critical and can be removed if - // it causes problems. This is meant to give a nicer error message for - // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component, - // ...)) which otherwise throws a "_processChildContext is not a function" - // exception. + if (currentTransitions !== null) { + var parentMarkerInstances = getMarkerInstances(); + var offscreenQueue = primaryChildFragment.updateQueue; - Object.defineProperty(fakeInternalInstance, "_processChildContext", { - enumerable: false, - value: function () { - throw new Error( - "_processChildContext is not available in React 16+. This likely " + - "means you have multiple copies of React and are attempting to nest " + - "a React 15 tree inside a React 16 tree using " + - "unstable_renderSubtreeIntoContainer, which isn't supported. Try " + - "to make sure you have only one copy of React (and ideally, switch " + - "to ReactDOM.createPortal)." + if (offscreenQueue === null) { + var newOffscreenQueue = { + transitions: currentTransitions, + markerInstances: parentMarkerInstances, + wakeables: null + }; + primaryChildFragment.updateQueue = newOffscreenQueue; + } else { + offscreenQueue.transitions = currentTransitions; + offscreenQueue.markerInstances = parentMarkerInstances; + } + } + } + + return fallbackFragment; + } else if (typeof nextProps.unstable_expectedLoadTime === "number") { + // This is a CPU-bound tree. Skip this tree and show a placeholder to + // unblock the surrounding content. Then immediately retry after the + // initial commit. + pushFallbackTreeSuspenseHandler(workInProgress); + + var _fallbackFragment = mountSuspenseFallbackChildren( + workInProgress, + nextPrimaryChildren, + nextFallbackChildren, + renderLanes ); - } - }); - Object.freeze(fakeInternalInstance); -} -function warnOnInvalidCallback$1(callback, callerName) { - { - if (callback === null || typeof callback === "function") { - return; + var _primaryChildFragment = workInProgress.child; + _primaryChildFragment.memoizedState = + mountSuspenseOffscreenState(renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; // TODO: Transition Tracing is not yet implemented for CPU Suspense. + // Since nothing actually suspended, there will nothing to ping this to + // get it started back up to attempt the next item. While in terms of + // priority this work has the same priority as this current render, it's + // not part of the same transition once the transition has committed. If + // it's sync, we still want to yield so that it can be painted. + // Conceptually, this is really the same as pinging. We can use any + // RetryLane even if it's the one currently rendering since we're leaving + // it behind on this node. + + workInProgress.lanes = SomeRetryLane; + return _fallbackFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren); } + } else { + // This is an update. + // Special path for hydration + var prevState = current.memoizedState; - var key = callerName + "_" + callback; + if (prevState !== null) { + var _dehydrated = prevState.dehydrated; - if (!didWarnOnInvalidCallback.has(key)) { - didWarnOnInvalidCallback.add(key); + if (_dehydrated !== null) { + return updateDehydratedSuspenseComponent( + current, + workInProgress, + didSuspend, + nextProps, + _dehydrated, + prevState, + renderLanes + ); + } + } - error( - "%s(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callerName, - callback + if (showFallback) { + pushFallbackTreeSuspenseHandler(workInProgress); + var _nextFallbackChildren = nextProps.fallback; + var _nextPrimaryChildren = nextProps.children; + var fallbackChildFragment = updateSuspenseFallbackChildren( + current, + workInProgress, + _nextPrimaryChildren, + _nextFallbackChildren, + renderLanes ); - } - } -} + var _primaryChildFragment2 = workInProgress.child; + var prevOffscreenState = current.child.memoizedState; + _primaryChildFragment2.memoizedState = + prevOffscreenState === null + ? mountSuspenseOffscreenState(renderLanes) + : updateSuspenseOffscreenState(prevOffscreenState, renderLanes); -function warnOnUndefinedDerivedState(type, partialState) { - { - if (partialState === undefined) { - var componentName = getComponentNameFromType(type) || "Component"; + if (enableTransitionTracing) { + var _currentTransitions = getPendingTransitions(); - if (!didWarnAboutUndefinedDerivedState.has(componentName)) { - didWarnAboutUndefinedDerivedState.add(componentName); + if (_currentTransitions !== null) { + var _parentMarkerInstances = getMarkerInstances(); - error( - "%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. " + - "You have returned undefined.", - componentName - ); + var _offscreenQueue = _primaryChildFragment2.updateQueue; + var currentOffscreenQueue = current.updateQueue; + + if (_offscreenQueue === null) { + var _newOffscreenQueue = { + transitions: _currentTransitions, + markerInstances: _parentMarkerInstances, + wakeables: null + }; + _primaryChildFragment2.updateQueue = _newOffscreenQueue; + } else if (_offscreenQueue === currentOffscreenQueue) { + // If the work-in-progress queue is the same object as current, we + // can't modify it without cloning it first. + var _newOffscreenQueue2 = { + transitions: _currentTransitions, + markerInstances: _parentMarkerInstances, + wakeables: + currentOffscreenQueue !== null + ? currentOffscreenQueue.wakeables + : null + }; + _primaryChildFragment2.updateQueue = _newOffscreenQueue2; + } else { + _offscreenQueue.transitions = _currentTransitions; + _offscreenQueue.markerInstances = _parentMarkerInstances; + } + } } + + _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree( + current, + renderLanes + ); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + var _nextPrimaryChildren2 = nextProps.children; + + var _primaryChildFragment3 = updateSuspensePrimaryChildren( + current, + workInProgress, + _nextPrimaryChildren2, + renderLanes + ); + + workInProgress.memoizedState = null; + return _primaryChildFragment3; } } } -function applyDerivedStateFromProps( +function mountSuspensePrimaryChildren( workInProgress, - ctor, - getDerivedStateFromProps, - nextProps + primaryChildren, + renderLanes ) { - var prevState = workInProgress.memoizedState; - var partialState = getDerivedStateFromProps(nextProps, prevState); - - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + var mode = workInProgress.mode; + var primaryChildProps = { + mode: "visible", + children: primaryChildren + }; + var primaryChildFragment = mountWorkInProgressOffscreenFiber( + primaryChildProps, + mode + ); + primaryChildFragment.return = workInProgress; + workInProgress.child = primaryChildFragment; + return primaryChildFragment; +} - try { - // Invoke the function an extra time to help detect side-effects. - partialState = getDerivedStateFromProps(nextProps, prevState); - } finally { - setIsStrictModeForDevtools(false); - } - } +function mountSuspenseFallbackChildren( + workInProgress, + primaryChildren, + fallbackChildren, + renderLanes +) { + var mode = workInProgress.mode; + var progressedPrimaryFragment = workInProgress.child; + var primaryChildProps = { + mode: "hidden", + children: primaryChildren + }; + var primaryChildFragment; + var fallbackChildFragment; - warnOnUndefinedDerivedState(ctor, partialState); - } // Merge the partial state and the previous state. + if ( + (mode & ConcurrentMode) === NoMode && + progressedPrimaryFragment !== null + ) { + // In legacy mode, we commit the primary tree as if it successfully + // completed, even though it's in an inconsistent state. + primaryChildFragment = progressedPrimaryFragment; + primaryChildFragment.childLanes = NoLanes; + primaryChildFragment.pendingProps = primaryChildProps; - 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. + if (workInProgress.mode & ProfileMode) { + // Reset the durations from the first pass so they aren't included in the + // final amounts. This seems counterintuitive, since we're intentionally + // not measuring part of the render phase, but this makes it match what we + // do in Concurrent Mode. + primaryChildFragment.actualDuration = 0; + primaryChildFragment.actualStartTime = -1; + primaryChildFragment.selfBaseDuration = 0; + primaryChildFragment.treeBaseDuration = 0; + } - if (workInProgress.lanes === NoLanes) { - // Queue is always non-null for classes - var updateQueue = workInProgress.updateQueue; - updateQueue.baseState = memoizedState; + fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + mode, + renderLanes, + null + ); + } else { + primaryChildFragment = mountWorkInProgressOffscreenFiber( + primaryChildProps, + mode + ); + fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + mode, + renderLanes, + null + ); } -} - -var classComponentUpdater = { - isMounted: isMounted, - // $FlowFixMe[missing-local-annot] - enqueueSetState: function (inst, payload, callback) { - var fiber = get(inst); - var lane = requestUpdateLane(fiber); - var update = createUpdate(lane); - update.payload = payload; - - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback$1(callback, "setState"); - } - update.callback = callback; - } + primaryChildFragment.return = workInProgress; + fallbackChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; + return fallbackChildFragment; +} - var root = enqueueUpdate(fiber, update, lane); +function mountWorkInProgressOffscreenFiber(offscreenProps, mode, renderLanes) { + // The props argument to `createFiberFromOffscreen` is `any` typed, so we use + // this wrapper function to constrain it. + return createFiberFromOffscreen(offscreenProps, mode, NoLanes, null); +} - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitions(root, fiber, lane); - } +function updateWorkInProgressOffscreenFiber(current, offscreenProps) { + // The props argument to `createWorkInProgress` is `any` typed, so we use this + // wrapper function to constrain it. + return createWorkInProgress(current, offscreenProps); +} +function updateSuspensePrimaryChildren( + current, + workInProgress, + primaryChildren, + renderLanes +) { + var currentPrimaryChildFragment = current.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + var primaryChildFragment = updateWorkInProgressOffscreenFiber( + currentPrimaryChildFragment, { - if (enableDebugTracing) { - if (fiber.mode & DebugTracingMode) { - var name = getComponentNameFromFiber(fiber) || "Unknown"; - logStateUpdateScheduled(name, lane, payload); - } - } - } - - if (enableSchedulingProfiler) { - markStateUpdateScheduled(fiber, lane); + mode: "visible", + children: primaryChildren } - }, - enqueueReplaceState: function (inst, payload, callback) { - var fiber = get(inst); - var lane = requestUpdateLane(fiber); - var update = createUpdate(lane); - update.tag = ReplaceState; - update.payload = payload; + ); - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback$1(callback, "replaceState"); - } + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + primaryChildFragment.lanes = renderLanes; + } - update.callback = callback; - } + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = null; - var root = enqueueUpdate(fiber, update, lane); + if (currentFallbackChildFragment !== null) { + // Delete the fallback child fragment + var deletions = workInProgress.deletions; - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitions(root, fiber, lane); + if (deletions === null) { + workInProgress.deletions = [currentFallbackChildFragment]; + workInProgress.flags |= ChildDeletion; + } else { + deletions.push(currentFallbackChildFragment); } + } - { - if (enableDebugTracing) { - if (fiber.mode & DebugTracingMode) { - var name = getComponentNameFromFiber(fiber) || "Unknown"; - logStateUpdateScheduled(name, lane, payload); - } - } - } + workInProgress.child = primaryChildFragment; + return primaryChildFragment; +} - if (enableSchedulingProfiler) { - markStateUpdateScheduled(fiber, lane); - } - }, - // $FlowFixMe[missing-local-annot] - enqueueForceUpdate: function (inst, callback) { - var fiber = get(inst); - var lane = requestUpdateLane(fiber); - var update = createUpdate(lane); - update.tag = ForceUpdate; +function updateSuspenseFallbackChildren( + current, + workInProgress, + primaryChildren, + fallbackChildren, + renderLanes +) { + var mode = workInProgress.mode; + var currentPrimaryChildFragment = current.child; + var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; + var primaryChildProps = { + mode: "hidden", + children: primaryChildren + }; + var primaryChildFragment; - if (callback !== undefined && callback !== null) { - { - warnOnInvalidCallback$1(callback, "forceUpdate"); - } + if ( + // In legacy mode, we commit the primary tree as if it successfully + // completed, even though it's in an inconsistent state. + (mode & ConcurrentMode) === NoMode && // Make sure we're on the second pass, i.e. the primary child fragment was + // already cloned. In legacy mode, the only case where this isn't true is + // when DevTools forces us to display a fallback; we skip the first render + // pass entirely and go straight to rendering the fallback. (In Concurrent + // Mode, SuspenseList can also trigger this scenario, but this is a legacy- + // only codepath.) + workInProgress.child !== currentPrimaryChildFragment + ) { + var progressedPrimaryFragment = workInProgress.child; + primaryChildFragment = progressedPrimaryFragment; + primaryChildFragment.childLanes = NoLanes; + primaryChildFragment.pendingProps = primaryChildProps; - update.callback = callback; - } + if (workInProgress.mode & ProfileMode) { + // Reset the durations from the first pass so they aren't included in the + // final amounts. This seems counterintuitive, since we're intentionally + // not measuring part of the render phase, but this makes it match what we + // do in Concurrent Mode. + primaryChildFragment.actualDuration = 0; + primaryChildFragment.actualStartTime = -1; + primaryChildFragment.selfBaseDuration = + currentPrimaryChildFragment.selfBaseDuration; + primaryChildFragment.treeBaseDuration = + currentPrimaryChildFragment.treeBaseDuration; + } // The fallback fiber was added as a deletion during the first pass. + // However, since we're going to remain on the fallback, we no longer want + // to delete it. - var root = enqueueUpdate(fiber, update, lane); + workInProgress.deletions = null; + } else { + primaryChildFragment = updateWorkInProgressOffscreenFiber( + currentPrimaryChildFragment, + primaryChildProps + ); // Since we're reusing a current tree, we need to reuse the flags, too. + // (We don't do this in legacy mode, because in legacy mode we don't re-use + // the current tree; see previous branch.) - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - entangleTransitions(root, fiber, lane); - } + primaryChildFragment.subtreeFlags = + currentPrimaryChildFragment.subtreeFlags & StaticMask; + } - { - if (enableDebugTracing) { - if (fiber.mode & DebugTracingMode) { - var name = getComponentNameFromFiber(fiber) || "Unknown"; - logForceUpdateScheduled(name, lane); - } - } - } + var fallbackChildFragment; - if (enableSchedulingProfiler) { - markForceUpdateScheduled(fiber, lane); - } + if (currentFallbackChildFragment !== null) { + fallbackChildFragment = createWorkInProgress( + currentFallbackChildFragment, + fallbackChildren + ); + } else { + fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + mode, + renderLanes, + null + ); // Needs a placement effect because the parent (the Suspense boundary) already + // mounted but this is a new fiber. + + fallbackChildFragment.flags |= Placement; } -}; -function checkShouldComponentUpdate( + fallbackChildFragment.return = workInProgress; + primaryChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; + return fallbackChildFragment; +} + +function retrySuspenseComponentWithoutHydrating( + current, workInProgress, - ctor, - oldProps, - newProps, - oldState, - newState, - nextContext + renderLanes, + recoverableError ) { - var instance = workInProgress.stateNode; + // Falling back to client rendering. Because this has performance + // implications, it's considered a recoverable error, even though the user + // likely won't observe anything wrong with the UI. + // + // The error is passed in as an argument to enforce that every caller provide + // a custom message, or explicitly opt out (currently the only path that opts + // out is legacy mode; every concurrent path provides an error). + if (recoverableError !== null) { + queueHydrationError(recoverableError); + } // This will add the old fiber to the deletion list - if (typeof instance.shouldComponentUpdate === "function") { - var shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - nextContext - ); + reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated. - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); + var nextProps = workInProgress.pendingProps; + var primaryChildren = nextProps.children; + var primaryChildFragment = mountSuspensePrimaryChildren( + workInProgress, + primaryChildren + ); // Needs a placement effect because the parent (the Suspense boundary) already + // mounted but this is a new fiber. - try { - // Invoke the function an extra time to help detect side-effects. - shouldUpdate = instance.shouldComponentUpdate( - newProps, - newState, - nextContext - ); - } finally { - setIsStrictModeForDevtools(false); - } - } + primaryChildFragment.flags |= Placement; + workInProgress.memoizedState = null; + return primaryChildFragment; +} - if (shouldUpdate === undefined) { - error( - "%s.shouldComponentUpdate(): Returned undefined instead of a " + - "boolean value. Make sure to return true or false.", - getComponentNameFromType(ctor) || "Component" - ); - } - } +function mountSuspenseFallbackAfterRetryWithoutHydrating( + current, + workInProgress, + primaryChildren, + fallbackChildren, + renderLanes +) { + var fiberMode = workInProgress.mode; + var primaryChildProps = { + mode: "visible", + children: primaryChildren + }; + var primaryChildFragment = mountWorkInProgressOffscreenFiber( + primaryChildProps, + fiberMode + ); + var fallbackChildFragment = createFiberFromFragment( + fallbackChildren, + fiberMode, + renderLanes, + null + ); // Needs a placement effect because the parent (the Suspense + // boundary) already mounted but this is a new fiber. - return shouldUpdate; - } + fallbackChildFragment.flags |= Placement; + primaryChildFragment.return = workInProgress; + fallbackChildFragment.return = workInProgress; + primaryChildFragment.sibling = fallbackChildFragment; + workInProgress.child = primaryChildFragment; - if (ctor.prototype && ctor.prototype.isPureReactComponent) { - return ( - !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) - ); + if ((workInProgress.mode & ConcurrentMode) !== NoMode) { + // We will have dropped the effect list which contains the + // deletion. We need to reconcile to delete the current child. + reconcileChildFibers(workInProgress, current.child, null, renderLanes); } - return true; + return fallbackChildFragment; } -function checkClassInstance(workInProgress, ctor, newProps) { - var instance = workInProgress.stateNode; - - { - var name = getComponentNameFromType(ctor) || "Component"; - var renderPresent = instance.render; - - if (!renderPresent) { - if (ctor.prototype && typeof ctor.prototype.render === "function") { - error( - "%s(...): No `render` method found on the returned component " + - "instance: did you accidentally return an object from the constructor?", - name - ); - } else { - error( - "%s(...): No `render` method found on the returned component " + - "instance: you may have forgotten to define `render`.", - name - ); - } - } - - if ( - instance.getInitialState && - !instance.getInitialState.isReactClassApproved && - !instance.state - ) { +function mountDehydratedSuspenseComponent( + workInProgress, + suspenseInstance, + renderLanes +) { + // 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. + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + { error( - "getInitialState was defined on %s, a plain JavaScript class. " + - "This is only supported for classes created using React.createClass. " + - "Did you mean to define a state property instead?", - name + "Cannot hydrate Suspense in legacy mode. Switch from " + + "ReactDOM.hydrate(element, container) to " + + "ReactDOMClient.hydrateRoot(container, )" + + ".render(element) or remove the Suspense components from " + + "the server rendered components." ); } - if ( - instance.getDefaultProps && - !instance.getDefaultProps.isReactClassApproved - ) { - error( - "getDefaultProps was defined on %s, a plain JavaScript class. " + - "This is only supported for classes created using React.createClass. " + - "Use a static property to define defaultProps instead.", - name - ); - } + workInProgress.lanes = laneToLanes(SyncLane); + } else if (isSuspenseInstanceFallback(suspenseInstance)) { + // This is a client-only boundary. Since we won't get any content from the server + // for this, we need to schedule that at a higher priority based on when it would + // have timed out. In theory we could render it in this pass but it would have the + // wrong priority associated with it and will prevent hydration of parent path. + // Instead, we'll leave work left on it to render it in a separate commit. + // TODO This time should be the time at which the server rendered response that is + // a parent to this boundary was displayed. However, since we currently don't have + // a protocol to transfer that time, we'll just estimate it by using the current + // time. This will mean that Suspense timeouts are slightly shifted to later than + // they should be. + // Schedule a normal pri update to render this content. + workInProgress.lanes = laneToLanes(DefaultHydrationLane); + } else { + // We'll continue hydrating the rest at offscreen priority since we'll already + // be showing the right content coming from the server, it is no rush. + workInProgress.lanes = laneToLanes(OffscreenLane); + } - if (instance.propTypes) { - error( - "propTypes was defined as an instance property on %s. Use a static " + - "property to define propTypes instead.", - name - ); - } + return null; +} - if (instance.contextType) { - error( - "contextType was defined as an instance property on %s. Use a static " + - "property to define contextType instead.", - name +function updateDehydratedSuspenseComponent( + current, + workInProgress, + didSuspend, + nextProps, + suspenseInstance, + suspenseState, + renderLanes +) { + if (!didSuspend) { + // This is the first render pass. Attempt to hydrate. + pushPrimaryTreeSuspenseHandler(workInProgress); // We should never be hydrating at this point because it is the first pass, + // but after we've already committed once. + + warnIfHydrating(); + + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + return retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + null ); } - { - if (instance.contextTypes) { - error( - "contextTypes was defined as an instance property on %s. Use a static " + - "property to define contextTypes instead.", - name - ); + if (isSuspenseInstanceFallback(suspenseInstance)) { + // This boundary is in a permanent fallback state. In this case, we'll never + // get an update and we'll never be able to hydrate the final content. Let's just try the + // client side render instead. + var digest, message, stack; + + { + var _getSuspenseInstanceF = + getSuspenseInstanceFallbackErrorDetails(suspenseInstance); + + digest = _getSuspenseInstanceF.digest; + message = _getSuspenseInstanceF.message; + stack = _getSuspenseInstanceF.stack; } - if ( - ctor.contextType && - ctor.contextTypes && - !didWarnAboutContextTypeAndContextTypes.has(ctor) - ) { - didWarnAboutContextTypeAndContextTypes.add(ctor); + var error; - error( - "%s declares both contextTypes and contextType static properties. " + - "The legacy contextTypes property will be ignored.", - name + if (message) { + // eslint-disable-next-line react-internal/prod-error-codes + error = new Error(message); + } else { + error = new Error( + "The server could not finish this Suspense boundary, likely " + + "due to an error during server rendering. Switched to " + + "client rendering." ); } - } - if (typeof instance.componentShouldUpdate === "function") { - error( - "%s has a method called " + - "componentShouldUpdate(). Did you mean shouldComponentUpdate()? " + - "The name is phrased as a question because the function is " + - "expected to return a value.", - name + error.digest = digest; + var capturedValue = createCapturedValue(error, digest, stack); + return retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + capturedValue ); } if ( - ctor.prototype && - ctor.prototype.isPureReactComponent && - typeof instance.shouldComponentUpdate !== "undefined" + enableLazyContextPropagation && // TODO: Factoring is a little weird, since we check this right below, too. + // But don't want to re-arrange the if-else chain until/unless this + // feature lands. + !didReceiveUpdate ) { - error( - "%s has a method called shouldComponentUpdate(). " + - "shouldComponentUpdate should not be used when extending React.PureComponent. " + - "Please extend React.Component if shouldComponentUpdate is used.", - getComponentNameFromType(ctor) || "A pure component" - ); - } + // We need to check if any children have context before we decide to bail + // out, so propagate the changes now. + lazilyPropagateParentContextChanges(current, workInProgress, renderLanes); + } // We use lanes 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. - if (typeof instance.componentDidUnmount === "function") { - error( - "%s has a method called " + - "componentDidUnmount(). But there is no such lifecycle method. " + - "Did you mean componentWillUnmount()?", - name - ); - } + var hasContextChanged = includesSomeLane(renderLanes, current.childLanes); - if (typeof instance.componentDidReceiveProps === "function") { - error( - "%s has a method called " + - "componentDidReceiveProps(). But there is no such lifecycle method. " + - "If you meant to update the state in response to changing props, " + - "use componentWillReceiveProps(). If you meant to fetch data or " + - "run side-effects or mutations after React has updated the UI, use componentDidUpdate().", - name - ); - } + if (didReceiveUpdate || hasContextChanged) { + // 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 a higher priority lane. + var root = getWorkInProgressRoot(); - if (typeof instance.componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "componentWillRecieveProps(). Did you mean componentWillReceiveProps()?", - name - ); - } + if (root !== null) { + var attemptHydrationAtLane = getBumpedLaneForHydration( + root, + renderLanes + ); - if (typeof instance.UNSAFE_componentWillRecieveProps === "function") { - error( - "%s has a method called " + - "UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?", - name - ); - } + if ( + attemptHydrationAtLane !== NoLane && + attemptHydrationAtLane !== suspenseState.retryLane + ) { + // Intentionally mutating since this render will get interrupted. This + // is one of the very rare times where we mutate the current tree + // during the render phase. + suspenseState.retryLane = attemptHydrationAtLane; // TODO: Ideally this would inherit the event time of the current render - var hasMutatedProps = instance.props !== newProps; + var eventTime = NoTimestamp; + enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); + scheduleUpdateOnFiber( + root, + current, + attemptHydrationAtLane, + eventTime + ); // Throw a special object that signals to the work loop that it should + // interrupt the current render. + // + // Because we're inside a React-only execution stack, we don't + // strictly need to throw here — we could instead modify some internal + // work loop state. But using an exception means we don't need to + // check for this case on every iteration of the work loop. So doing + // it this way moves the check out of the fast path. - if (instance.props !== undefined && hasMutatedProps) { - error( - "%s(...): When calling super() in `%s`, make sure to pass " + - "up the same props that your component's constructor was passed.", - name, - name - ); - } + throw SelectiveHydrationException; + } + } // If we did not selectively hydrate, we'll continue rendering without + // hydrating. Mark this tree as suspended to prevent it from committing + // outside a transition. + // + // This path should only happen if the hydration lane already suspended. + // Currently, it also happens during sync updates because there is no + // hydration lane for sync updates. + // TODO: We should ideally have a sync hydration lane that we can apply to do + // a pass where we hydrate this subtree in place using the previous Context and then + // reapply the update afterwards. - if (instance.defaultProps) { - error( - "Setting defaultProps as an instance property on %s is not supported and will be ignored." + - " Instead, define defaultProps as a static property on %s.", - name, - name + renderDidSuspendDelayIfPossible(); + return retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + null ); - } - - if ( - typeof instance.getSnapshotBeforeUpdate === "function" && - typeof instance.componentDidUpdate !== "function" && - !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor) - ) { - didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor); + } else if (isSuspenseInstancePending(suspenseInstance)) { + // This component is still pending more data from the server, so we can't hydrate its + // content. We treat it as if this component suspended itself. It might seem as if + // we could just try to render it client-side instead. However, this will perform a + // lot of unnecessary work and is unlikely to complete since it often will suspend + // on missing data anyway. Additionally, the server might be able to render more + // than we can on the client yet. In that case we'd end up with more fallback states + // on the client than if we just leave it alone. If the server times out or errors + // these should update this boundary to the permanent Fallback state instead. + // Mark it as having captured (i.e. suspended). + workInProgress.flags |= DidCapture; // Leave the child in place. I.e. the dehydrated fragment. - error( - "%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). " + - "This component defines getSnapshotBeforeUpdate() only.", - getComponentNameFromType(ctor) - ); - } + workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. - if (typeof instance.getDerivedStateFromProps === "function") { - error( - "%s: getDerivedStateFromProps() is defined as an instance method " + - "and will be ignored. Instead, declare it as a static method.", - name + var retry = retryDehydratedSuspenseBoundary.bind(null, current); + registerSuspenseInstanceRetry(suspenseInstance, retry); + return null; + } else { + // This is the first attempt. + reenterHydrationStateFromDehydratedSuspenseInstance( + workInProgress, + suspenseInstance, + suspenseState.treeContext ); - } + var primaryChildren = nextProps.children; + var primaryChildFragment = mountSuspensePrimaryChildren( + workInProgress, + primaryChildren + ); // Mark the children as hydrating. This is a fast path to know whether this + // tree is part of a hydrating tree. This is used to determine if a child + // node has fully mounted yet, and for scheduling event replaying. + // Conceptually this is similar to Placement in that a new subtree is + // inserted into the React tree here. It just happens to not need DOM + // mutations because it already exists. - if (typeof instance.getDerivedStateFromError === "function") { - error( - "%s: getDerivedStateFromError() is defined as an instance method " + - "and will be ignored. Instead, declare it as a static method.", - name - ); + primaryChildFragment.flags |= Hydrating; + return primaryChildFragment; } + } else { + // This is the second render pass. We already attempted to hydrated, but + // something either suspended or errored. + if (workInProgress.flags & ForceClientRender) { + // Something errored during hydration. Try again without hydrating. + pushPrimaryTreeSuspenseHandler(workInProgress); + workInProgress.flags &= ~ForceClientRender; - if (typeof ctor.getSnapshotBeforeUpdate === "function") { - error( - "%s: getSnapshotBeforeUpdate() is defined as a static method " + - "and will be ignored. Instead, declare it as an instance method.", - name + var _capturedValue = createCapturedValue( + new Error( + "There was an error while hydrating this Suspense boundary. " + + "Switched to client rendering." + ) ); - } - - var state = instance.state; - - if (state && (typeof state !== "object" || isArray(state))) { - error("%s.state: must be set to an object or null", name); - } - if ( - typeof instance.getChildContext === "function" && - typeof ctor.childContextTypes !== "object" - ) { - error( - "%s.getChildContext(): childContextTypes must be defined in order to " + - "use getChildContext().", - name + return retrySuspenseComponentWithoutHydrating( + current, + workInProgress, + renderLanes, + _capturedValue ); - } - } -} - -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); - - { - instance._reactInternalInstance = fakeInternalInstance; - } -} - -function constructClassInstance(workInProgress, ctor, props) { - var isLegacyContextConsumer = false; - var unmaskedContext = emptyContextObject; - var context = emptyContextObject; - var contextType = ctor.contextType; - - { - if ("contextType" in ctor) { - var isValid = // Allow null for conditional declaration - contextType === null || - (contextType !== undefined && - contextType.$$typeof === REACT_CONTEXT_TYPE && - contextType._context === undefined); // Not a - - if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) { - didWarnAboutInvalidateContextType.add(ctor); - var addendum = ""; - - if (contextType === undefined) { - addendum = - " However, it is set to undefined. " + - "This can be caused by a typo or by mixing up named and default imports. " + - "This can also happen due to a circular dependency, so " + - "try moving the createContext() call to a separate file."; - } else if (typeof contextType !== "object") { - addendum = " However, it is set to a " + typeof contextType + "."; - } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) { - addendum = " Did you accidentally pass the Context.Provider instead?"; - } else if (contextType._context !== undefined) { - // - addendum = " Did you accidentally pass the Context.Consumer instead?"; - } else { - addendum = - " However, it is set to an object with keys {" + - Object.keys(contextType).join(", ") + - "}."; - } + } else if (workInProgress.memoizedState !== null) { + // Something suspended and we should still be in dehydrated mode. + // Leave the existing child in place. + // Push to avoid a mismatch + pushFallbackTreeSuspenseHandler(workInProgress); + workInProgress.child = current.child; // The dehydrated completion pass expects this flag to be there + // but the normal suspense pass doesn't. - error( - "%s defines an invalid contextType. " + - "contextType should point to the Context object returned by React.createContext().%s", - getComponentNameFromType(ctor) || "Component", - addendum + workInProgress.flags |= DidCapture; + return null; + } else { + // Suspended but we should no longer be in dehydrated mode. + // Therefore we now have to render the fallback. + pushFallbackTreeSuspenseHandler(workInProgress); + var nextPrimaryChildren = nextProps.children; + var nextFallbackChildren = nextProps.fallback; + var fallbackChildFragment = + mountSuspenseFallbackAfterRetryWithoutHydrating( + current, + workInProgress, + nextPrimaryChildren, + nextFallbackChildren, + renderLanes ); - } - } - } - - 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; - } - - var instance = new ctor(props, context); // Instantiate twice to help detect side-effects. - - { - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); - - try { - instance = new ctor(props, context); // eslint-disable-line no-new - } finally { - setIsStrictModeForDevtools(false); - } + var _primaryChildFragment4 = workInProgress.child; + _primaryChildFragment4.memoizedState = + mountSuspenseOffscreenState(renderLanes); + workInProgress.memoizedState = SUSPENDED_MARKER; + return fallbackChildFragment; } } +} - var state = (workInProgress.memoizedState = - instance.state !== null && instance.state !== undefined - ? instance.state - : null); - adoptClassInstance(workInProgress, instance); +function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - { - if (typeof ctor.getDerivedStateFromProps === "function" && state === null) { - var componentName = getComponentNameFromType(ctor) || "Component"; + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } - if (!didWarnAboutUninitializedState.has(componentName)) { - didWarnAboutUninitializedState.add(componentName); + scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot); +} - error( - "`%s` uses `getDerivedStateFromProps` but its initial state is " + - "%s. This is not recommended. Instead, define the initial state by " + - "assigning an object to `this.state` in the constructor of `%s`. " + - "This ensures that `getDerivedStateFromProps` arguments have a consistent shape.", - componentName, - instance.state === null ? "null" : "undefined", - componentName - ); - } - } // If new component APIs are defined, "unsafe" lifecycles won't be called. - // Warn about these lifecycles if they are present. - // Don't warn about react-lifecycles-compat polyfilled methods though. +function propagateSuspenseContextChange( + workInProgress, + firstChild, + renderLanes +) { + // Mark any Suspense boundaries with fallbacks as having work to do. + // If they were previously forced into fallbacks, they may now be able + // to unblock. + var node = firstChild; - if ( - typeof ctor.getDerivedStateFromProps === "function" || - typeof instance.getSnapshotBeforeUpdate === "function" - ) { - var foundWillMountName = null; - var foundWillReceivePropsName = null; - var foundWillUpdateName = null; + while (node !== null) { + if (node.tag === SuspenseComponent) { + var state = node.memoizedState; - if ( - typeof instance.componentWillMount === "function" && - instance.componentWillMount.__suppressDeprecationWarning !== true - ) { - foundWillMountName = "componentWillMount"; - } else if (typeof instance.UNSAFE_componentWillMount === "function") { - foundWillMountName = "UNSAFE_componentWillMount"; + if (state !== null) { + scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); } + } else if (node.tag === SuspenseListComponent) { + // If the tail is hidden there might not be an Suspense boundaries + // to schedule work on. In this case we have to schedule it on the + // list itself. + // We don't have to traverse to the children of the list since + // the list will propagate the change when it rerenders. + scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } - if ( - typeof instance.componentWillReceiveProps === "function" && - instance.componentWillReceiveProps.__suppressDeprecationWarning !== true - ) { - foundWillReceivePropsName = "componentWillReceiveProps"; - } else if ( - typeof instance.UNSAFE_componentWillReceiveProps === "function" - ) { - foundWillReceivePropsName = "UNSAFE_componentWillReceiveProps"; - } + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if ( - typeof instance.componentWillUpdate === "function" && - instance.componentWillUpdate.__suppressDeprecationWarning !== true - ) { - foundWillUpdateName = "componentWillUpdate"; - } else if (typeof instance.UNSAFE_componentWillUpdate === "function") { - foundWillUpdateName = "UNSAFE_componentWillUpdate"; + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; } - if ( - foundWillMountName !== null || - foundWillReceivePropsName !== null || - foundWillUpdateName !== null - ) { - var _componentName = getComponentNameFromType(ctor) || "Component"; - - var newApiName = - typeof ctor.getDerivedStateFromProps === "function" - ? "getDerivedStateFromProps()" - : "getSnapshotBeforeUpdate()"; - - if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) { - didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName); - - error( - "Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n" + - "%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n" + - "The above lifecycles should be removed. Learn more about this warning here:\n" + - "https://reactjs.org/link/unsafe-component-lifecycles", - _componentName, - newApiName, - foundWillMountName !== null ? "\n " + foundWillMountName : "", - foundWillReceivePropsName !== null - ? "\n " + foundWillReceivePropsName - : "", - foundWillUpdateName !== null ? "\n " + foundWillUpdateName : "" - ); - } - } - } - } // Cache unmasked context so we can avoid recreating masked context unless necessary. - // ReactFiberContext usually updates this cache but can't for newly-created instances. + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow - if (isLegacyContextConsumer) { - cacheContext(workInProgress, unmaskedContext, context); + node.sibling.return = node.return; + node = node.sibling; } - - return instance; } -function callComponentWillMount(workInProgress, instance) { - var oldState = instance.state; - - if (typeof instance.componentWillMount === "function") { - instance.componentWillMount(); - } +function findLastContentRow(firstChild) { + // This is going to find the last row among these children that is already + // showing content on the screen, as opposed to being in fallback state or + // new. If a row has multiple Suspense boundaries, any of them being in the + // fallback state, counts as the whole row being in a fallback state. + // Note that the "rows" will be workInProgress, but any nested children + // will still be current since we haven't rendered them yet. The mounted + // order may not be the same as the new order. We use the new order. + var row = firstChild; + var lastContentRow = null; - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. - if (oldState !== instance.state) { - { - error( - "%s.componentWillMount(): Assigning directly to this.state is " + - "deprecated (except inside a component's " + - "constructor). Use setState instead.", - getComponentNameFromFiber(workInProgress) || "Component" - ); + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + lastContentRow = row; } - classComponentUpdater.enqueueReplaceState(instance, instance.state, null); + row = row.sibling; } + + return lastContentRow; } -function callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext -) { - var oldState = instance.state; +function validateRevealOrder(revealOrder) { + { + if ( + revealOrder !== undefined && + revealOrder !== "forwards" && + revealOrder !== "backwards" && + revealOrder !== "together" && + !didWarnAboutRevealOrder[revealOrder] + ) { + didWarnAboutRevealOrder[revealOrder] = true; - if (typeof instance.componentWillReceiveProps === "function") { - instance.componentWillReceiveProps(newProps, nextContext); - } + if (typeof revealOrder === "string") { + switch (revealOrder.toLowerCase()) { + case "together": + case "forwards": + case "backwards": { + error( + '"%s" is not a valid value for revealOrder on . ' + + 'Use lowercase "%s" instead.', + revealOrder, + revealOrder.toLowerCase() + ); - if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { - instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); - } + break; + } - if (instance.state !== oldState) { - { - var componentName = - getComponentNameFromFiber(workInProgress) || "Component"; + case "forward": + case "backward": { + error( + '"%s" is not a valid value for revealOrder on . ' + + 'React uses the -s suffix in the spelling. Use "%ss" instead.', + revealOrder, + revealOrder.toLowerCase() + ); - if (!didWarnAboutStateAssignmentForComponent.has(componentName)) { - didWarnAboutStateAssignmentForComponent.add(componentName); + break; + } + + default: + error( + '"%s" is not a supported revealOrder on . ' + + 'Did you mean "together", "forwards" or "backwards"?', + revealOrder + ); + break; + } + } else { error( - "%s.componentWillReceiveProps(): Assigning directly to " + - "this.state is deprecated (except inside a component's " + - "constructor). Use setState instead.", - componentName + "%s is not a supported value for revealOrder on . " + + 'Did you mean "together", "forwards" or "backwards"?', + revealOrder ); } } - - classComponentUpdater.enqueueReplaceState(instance, instance.state, null); - } -} // Invokes the mount life-cycles on a previously never rendered instance. - -function mountClassInstance(workInProgress, ctor, newProps, renderLanes) { - { - checkClassInstance(workInProgress, ctor, newProps); - } - - var instance = workInProgress.stateNode; - instance.props = newProps; - instance.state = workInProgress.memoizedState; - instance.refs = {}; - initializeUpdateQueue(workInProgress); - 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); } +} +function validateTailOptions(tailMode, revealOrder) { { - if (instance.state === newProps) { - var componentName = getComponentNameFromType(ctor) || "Component"; + if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { + if (tailMode !== "collapsed" && tailMode !== "hidden") { + didWarnAboutTailOptions[tailMode] = true; - if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) { - didWarnAboutDirectlyAssigningPropsToState.add(componentName); + error( + '"%s" is not a supported value for tail on . ' + + 'Did you mean "collapsed" or "hidden"?', + tailMode + ); + } else if (revealOrder !== "forwards" && revealOrder !== "backwards") { + didWarnAboutTailOptions[tailMode] = true; error( - "%s: It is not recommended to assign props directly to state " + - "because updates to props won't be reflected in state. " + - "In most cases, it is better to use props directly.", - componentName + ' is only valid if revealOrder is ' + + '"forwards" or "backwards". ' + + 'Did you mean to specify revealOrder="forwards"?', + tailMode ); } } - - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning( - workInProgress, - instance - ); - } - - ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( - workInProgress, - instance - ); - } - - 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. - - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - instance.state = workInProgress.memoizedState; - } - - if (typeof instance.componentDidMount === "function") { - var fiberFlags = Update | LayoutStatic; - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } - - workInProgress.flags |= fiberFlags; } } -function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) { - var instance = workInProgress.stateNode; - var oldProps = workInProgress.memoizedProps; - instance.props = oldProps; - var oldContext = instance.context; - var contextType = ctor.contextType; - var nextContext = emptyContextObject; - - if (typeof contextType === "object" && contextType !== null) { - nextContext = readContext(contextType); - } else { - var nextLegacyUnmaskedContext = getUnmaskedContext( - workInProgress, - ctor, - true - ); - nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); - } +function validateSuspenseListNestedChild(childSlot, index) { + { + var isAnArray = isArray(childSlot); + var isIterable = + !isAnArray && typeof getIteratorFn(childSlot) === "function"; - 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 (isAnArray || isIterable) { + var type = isAnArray ? "array" : "iterable"; - if ( - !hasNewLifecycles && - (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") - ) { - if (oldProps !== newProps || oldContext !== nextContext) { - callComponentWillReceiveProps( - workInProgress, - instance, - newProps, - nextContext + error( + "A nested %s was passed to row #%s in . Wrap it in " + + "an additional SuspenseList to configure its revealOrder: " + + " ... " + + "{%s} ... " + + "", + type, + index, + type ); - } - } - - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - 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") { - var fiberFlags = Update | LayoutStatic; - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - fiberFlags |= MountLayoutDev; - } - workInProgress.flags |= fiberFlags; + return false; } - - 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 - ); + return true; +} - if (shouldUpdate) { - // In order to support react-lifecycles-compat polyfilled components, - // Unsafe lifecycles should not be invoked for components using the new APIs. +function validateSuspenseListChildren(children, revealOrder) { + { if ( - !hasNewLifecycles && - (typeof instance.UNSAFE_componentWillMount === "function" || - typeof instance.componentWillMount === "function") + (revealOrder === "forwards" || revealOrder === "backwards") && + children !== undefined && + children !== null && + children !== false ) { - if (typeof instance.componentWillMount === "function") { - instance.componentWillMount(); - } - - if (typeof instance.UNSAFE_componentWillMount === "function") { - instance.UNSAFE_componentWillMount(); - } - } - - if (typeof instance.componentDidMount === "function") { - var _fiberFlags = Update | LayoutStatic; - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - _fiberFlags |= MountLayoutDev; - } - - workInProgress.flags |= _fiberFlags; - } - } 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") { - var _fiberFlags2 = Update | LayoutStatic; - - if ((workInProgress.mode & StrictEffectsMode) !== NoMode) { - _fiberFlags2 |= MountLayoutDev; - } + if (isArray(children)) { + for (var i = 0; i < children.length; i++) { + if (!validateSuspenseListNestedChild(children[i], i)) { + return; + } + } + } else { + var iteratorFn = getIteratorFn(children); - workInProgress.flags |= _fiberFlags2; - } // If shouldComponentUpdate returned false, we should still update the - // memoized state to indicate that this work can be reused. + if (typeof iteratorFn === "function") { + var childrenIterator = iteratorFn.call(children); - workInProgress.memoizedProps = newProps; - workInProgress.memoizedState = newState; - } // Update the existing instance's state, props, and context pointers even - // if shouldComponentUpdate returns false. + if (childrenIterator) { + var step = childrenIterator.next(); + var _i = 0; - instance.props = newProps; - instance.state = newState; - instance.context = nextContext; - return shouldUpdate; -} // Invokes the update life-cycles and returns false if it shouldn't rerender. + for (; !step.done; step = childrenIterator.next()) { + if (!validateSuspenseListNestedChild(step.value, _i)) { + return; + } -function updateClassInstance( - current, + _i++; + } + } + } else { + error( + 'A single row was passed to a . ' + + "This is not useful since it needs multiple rows. " + + "Did you mean to pass multiple children or an array?", + revealOrder + ); + } + } + } + } +} + +function initSuspenseListRenderState( workInProgress, - ctor, - newProps, - renderLanes + isBackwards, + tail, + lastContentRow, + tailMode ) { - var instance = workInProgress.stateNode; - cloneUpdateQueue(current, workInProgress); - var unresolvedOldProps = workInProgress.memoizedProps; - var oldProps = - workInProgress.type === workInProgress.elementType - ? unresolvedOldProps - : resolveDefaultProps(workInProgress.type, unresolvedOldProps); - instance.props = oldProps; - var unresolvedNewProps = workInProgress.pendingProps; - var oldContext = instance.context; - var contextType = ctor.contextType; - var nextContext = emptyContextObject; + var renderState = workInProgress.memoizedState; - if (typeof contextType === "object" && contextType !== null) { - nextContext = readContext(contextType); + if (renderState === null) { + workInProgress.memoizedState = { + isBackwards: isBackwards, + rendering: null, + renderingStartTime: 0, + last: lastContentRow, + tail: tail, + tailMode: tailMode + }; } else { - var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); - nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); + // We can reuse the existing object from previous renders. + renderState.isBackwards = isBackwards; + renderState.rendering = null; + renderState.renderingStartTime = 0; + renderState.last = lastContentRow; + renderState.tail = tail; + renderState.tailMode = tailMode; } +} // This can end up rendering this component multiple passes. +// The first pass splits the children fibers into two sets. A head and tail. +// We first render the head. If anything is in fallback state, we do another +// pass through beginWork to rerender all children (including the tail) with +// the force suspend context. If the first render didn't have anything in +// in fallback state. Then we render each row in the tail one-by-one. +// That happens in the completeWork phase without going back to beginWork. - 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. +function updateSuspenseListComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; + var revealOrder = nextProps.revealOrder; + var tailMode = nextProps.tail; + var newChildren = nextProps.children; + validateRevealOrder(revealOrder); + validateTailOptions(tailMode, revealOrder); + validateSuspenseListChildren(newChildren, revealOrder); + reconcileChildren(current, workInProgress, newChildren, renderLanes); + var suspenseContext = suspenseStackCursor.current; + var shouldForceFallback = hasSuspenseListContext( + suspenseContext, + ForceSuspenseFallback + ); - if ( - !hasNewLifecycles && - (typeof instance.UNSAFE_componentWillReceiveProps === "function" || - typeof instance.componentWillReceiveProps === "function") - ) { - if ( - unresolvedOldProps !== unresolvedNewProps || - oldContext !== nextContext - ) { - callComponentWillReceiveProps( + if (shouldForceFallback) { + suspenseContext = setShallowSuspenseListContext( + suspenseContext, + ForceSuspenseFallback + ); + workInProgress.flags |= DidCapture; + } else { + var didSuspendBefore = + current !== null && (current.flags & DidCapture) !== NoFlags$1; + + if (didSuspendBefore) { + // If we previously forced a fallback, we need to schedule work + // on any nested boundaries to let them know to try to render + // again. This is the same as context updating. + propagateSuspenseContextChange( workInProgress, - instance, - newProps, - nextContext + workInProgress.child, + renderLanes ); } + + suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); } - resetHasForceUpdateBeforeProcessing(); - var oldState = workInProgress.memoizedState; - var newState = (instance.state = oldState); - processUpdateQueue(workInProgress, newProps, instance, renderLanes); - newState = workInProgress.memoizedState; + pushSuspenseListContext(workInProgress, suspenseContext); - if ( - unresolvedOldProps === unresolvedNewProps && - oldState === newState && - !hasContextChanged() && - !checkHasForceUpdateAfterProcessing() && - !( - enableLazyContextPropagation && - current !== null && - current.dependencies !== null && - checkIfContextChanged(current.dependencies) - ) - ) { - // 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 ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Update; - } - } + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + // In legacy mode, SuspenseList doesn't work so we just + // use make it a noop by treating it as the default revealOrder. + workInProgress.memoizedState = null; + } else { + switch (revealOrder) { + case "forwards": { + var lastContentRow = findLastContentRow(workInProgress.child); + var tail; - if (typeof instance.getSnapshotBeforeUpdate === "function") { - if ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Snapshot; + if (lastContentRow === null) { + // The whole list is part of the tail. + // TODO: We could fast path by just rendering the tail now. + tail = workInProgress.child; + workInProgress.child = null; + } else { + // Disconnect the tail rows after the content row. + // We're going to render them separately later. + tail = lastContentRow.sibling; + lastContentRow.sibling = null; + } + + initSuspenseListRenderState( + workInProgress, + false, // isBackwards + tail, + lastContentRow, + tailMode + ); + break; } - } - return false; - } + case "backwards": { + // We're going to find the first row that has existing content. + // At the same time we're going to reverse the list of everything + // we pass in the meantime. That's going to be our tail in reverse + // order. + var _tail = null; + var row = workInProgress.child; + workInProgress.child = null; - if (typeof getDerivedStateFromProps === "function") { - applyDerivedStateFromProps( - workInProgress, - ctor, - getDerivedStateFromProps, - newProps - ); - newState = workInProgress.memoizedState; - } + while (row !== null) { + var currentRow = row.alternate; // New rows can't be content rows. - var shouldUpdate = - checkHasForceUpdateAfterProcessing() || - checkShouldComponentUpdate( - workInProgress, - ctor, - oldProps, - newProps, - oldState, - newState, - nextContext - ) || // TODO: In some cases, we'll end up checking if context has changed twice, - // both before and after `shouldComponentUpdate` has been called. Not ideal, - // but I'm loath to refactor this function. This only happens for memoized - // components so it's not that common. - (enableLazyContextPropagation && - current !== null && - current.dependencies !== null && - checkIfContextChanged(current.dependencies)); + if (currentRow !== null && findFirstSuspended(currentRow) === null) { + // This is the beginning of the main content. + workInProgress.child = row; + break; + } - 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") - ) { - if (typeof instance.componentWillUpdate === "function") { - instance.componentWillUpdate(newProps, newState, nextContext); - } + var nextRow = row.sibling; + row.sibling = _tail; + _tail = row; + row = nextRow; + } // TODO: If workInProgress.child is null, we can continue on the tail immediately. - if (typeof instance.UNSAFE_componentWillUpdate === "function") { - instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); + initSuspenseListRenderState( + workInProgress, + true, // isBackwards + _tail, + null, // last + tailMode + ); + break; } - } - - if (typeof instance.componentDidUpdate === "function") { - workInProgress.flags |= Update; - } - if (typeof instance.getSnapshotBeforeUpdate === "function") { - workInProgress.flags |= 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 ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Update; + case "together": { + initSuspenseListRenderState( + workInProgress, + false, // isBackwards + null, // tail + null, // last + undefined + ); + break; } - } - if (typeof instance.getSnapshotBeforeUpdate === "function") { - if ( - unresolvedOldProps !== current.memoizedProps || - oldState !== current.memoizedState - ) { - workInProgress.flags |= Snapshot; + default: { + // The default reveal order is the same as not having + // a boundary. + workInProgress.memoizedState = null; } - } // 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; + return workInProgress.child; } -function createCapturedValueAtFiber(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), - digest: null - }; -} -function createCapturedValue(value, digest, stack) { - return { - value: value, - source: null, - stack: stack != null ? stack : null, - digest: digest != null ? digest : null - }; -} +function updatePortalComponent(current, workInProgress, renderLanes) { + pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + var nextChildren = workInProgress.pendingProps; -var ReactFiberErrorDialogWWW = require("ReactFiberErrorDialog"); + if (current === 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, + renderLanes + ); + } else { + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + } -if (typeof ReactFiberErrorDialogWWW.showErrorDialog !== "function") { - throw new Error( - "Expected ReactFiberErrorDialog.showErrorDialog to be a function." - ); + return workInProgress.child; } -function showErrorDialog(boundary, errorInfo) { - var capturedError = { - componentStack: errorInfo.stack !== null ? errorInfo.stack : "", - error: errorInfo.value, - errorBoundary: - boundary !== null && boundary.tag === ClassComponent - ? boundary.stateNode - : null - }; - return ReactFiberErrorDialogWWW.showErrorDialog(capturedError); -} +var hasWarnedAboutUsingNoValuePropOnContextProvider = false; -function logCapturedError(boundary, errorInfo) { - try { - var logError = showErrorDialog(boundary, errorInfo); // Allow injected showErrorDialog() to prevent default console.error logging. - // This enables renderers like ReactNative to better manage redbox behavior. +function updateContextProvider(current, workInProgress, renderLanes) { + var providerType = workInProgress.type; + var context = providerType._context; + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; + var newValue = newProps.value; - if (logError === false) { - return; - } + { + if (!("value" in newProps)) { + if (!hasWarnedAboutUsingNoValuePropOnContextProvider) { + hasWarnedAboutUsingNoValuePropOnContextProvider = true; - var error = errorInfo.value; + error( + "The `value` prop is required for the ``. Did you misspell it or forget to pass it?" + ); + } + } - if (true) { - var source = errorInfo.source; - var stack = errorInfo.stack; - var componentStack = stack !== null ? stack : ""; // Browsers support silencing uncaught errors by calling - // `preventDefault()` in window `error` handler. - // We record this information as an expando on the error. + var providerPropTypes = workInProgress.type.propTypes; - if (error != null && error._suppressLogging) { - if (boundary.tag === ClassComponent) { - // The error is recoverable and was silenced. - // Ignore it and don't print the stack addendum. - // This is handy for testing error boundaries without noise. - return; - } // The error is fatal. Since the silencing might have - // been accidental, we'll surface it anyway. - // However, the browser would have silenced the original error - // so we'll print it first, and then print the stack addendum. + if (providerPropTypes) { + checkPropTypes(providerPropTypes, newProps, "prop", "Context.Provider"); + } + } - console["error"](error); // Don't transform to our wrapper - // For a more detailed description of this block, see: - // https://github.com/facebook/react/pull/13384 - } + pushProvider(workInProgress, context, newValue); - var componentName = source ? getComponentNameFromFiber(source) : null; - var componentNameMessage = componentName - ? "The above error occurred in the <" + componentName + "> component:" - : "The above error occurred in one of your React components:"; - var errorBoundaryMessage; + if (enableLazyContextPropagation); + else { + if (oldProps !== null) { + var oldValue = oldProps.value; - if (boundary.tag === HostRoot) { - errorBoundaryMessage = - "Consider adding an error boundary to your tree to customize error handling behavior.\n" + - "Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries."; + if (objectIs(oldValue, newValue)) { + // No change. Bailout early if children are the same. + if (oldProps.children === newProps.children && !hasContextChanged()) { + return bailoutOnAlreadyFinishedWork( + current, + workInProgress, + renderLanes + ); + } } else { - var errorBoundaryName = - getComponentNameFromFiber(boundary) || "Anonymous"; - errorBoundaryMessage = - "React will try to recreate this component tree from scratch " + - ("using the error boundary you provided, " + errorBoundaryName + "."); + // The context value changed. Search for matching consumers and schedule + // them to update. + propagateContextChange(workInProgress, context, renderLanes); } - - var combinedMessage = - componentNameMessage + - "\n" + - componentStack + - "\n\n" + - ("" + errorBoundaryMessage); // In development, we provide our own message with just the component stack. - // We don't include the original error message and JS stack because the browser - // has already printed it. Even if the application swallows the error, it is still - // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils. - - console["error"](combinedMessage); // Don't transform to our wrapper } - } 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; - }); } -} - -function createRootErrorUpdate(fiber, errorInfo, lane) { - var update = createUpdate(lane); // 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); - logCapturedError(fiber, errorInfo); - }; - return update; + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; } -function createClassErrorUpdate(fiber, errorInfo, lane) { - var update = createUpdate(lane); - update.tag = CaptureUpdate; - var getDerivedStateFromError = fiber.type.getDerivedStateFromError; +var hasWarnedAboutUsingContextAsConsumer = false; - if (typeof getDerivedStateFromError === "function") { - var error$1 = errorInfo.value; +function updateContextConsumer(current, workInProgress, renderLanes) { + 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. - update.payload = function () { - return getDerivedStateFromError(error$1); - }; + { + if (context._context === undefined) { + // This may be because it's a Context (rather than a Consumer). + // Or it may be because it's older React where they're the same thing. + // We only want to warn if we're sure it's a new React. + if (context !== context.Consumer) { + if (!hasWarnedAboutUsingContextAsConsumer) { + hasWarnedAboutUsingContextAsConsumer = true; - update.callback = function () { - { - markFailedErrorBoundaryForHotReloading(fiber); + error( + "Rendering directly is not supported and will be removed in " + + "a future major release. Did you mean to render instead?" + ); + } } - - logCapturedError(fiber, errorInfo); - }; + } else { + context = context._context; + } } - var inst = fiber.stateNode; + var newProps = workInProgress.pendingProps; + var render = newProps.children; - if (inst !== null && typeof inst.componentDidCatch === "function") { - // $FlowFixMe[missing-this-annot] - update.callback = function callback() { - { - markFailedErrorBoundaryForHotReloading(fiber); - } + { + if (typeof render !== "function") { + error( + "A context consumer was rendered with multiple children, or a child " + + "that isn't a function. A context consumer expects a single child " + + "that is a function. If you did pass a function, make sure there " + + "is no trailing or leading whitespace around it." + ); + } + } - logCapturedError(fiber, errorInfo); + prepareToReadContext(workInProgress, renderLanes); + var newValue = readContext(context); - 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); - } + if (enableSchedulingProfiler) { + markComponentRenderStarted(workInProgress); + } - var error$1 = errorInfo.value; - var stack = errorInfo.stack; - this.componentDidCatch(error$1, { - componentStack: stack !== null ? stack : "" - }); + var newChildren; - { - if (typeof getDerivedStateFromError !== "function") { - // If componentDidCatch is the only error boundary method defined, - // then it needs to call setState to recover from errors. - // If no state update is scheduled then the boundary will swallow the error. - if (!includesSomeLane(fiber.lanes, SyncLane)) { - error( - "%s: Error boundaries should implement getDerivedStateFromError(). " + - "In that method, return a state update to display an error message or fallback UI.", - getComponentNameFromFiber(fiber) || "Unknown" - ); - } - } - } - }; + { + ReactCurrentOwner$2.current = workInProgress; + setIsRendering(true); + newChildren = render(newValue); + setIsRendering(false); } - return update; -} + if (enableSchedulingProfiler) { + markComponentRenderStopped(); + } // React DevTools reads this flag. -function resetSuspendedComponent(sourceFiber, rootRenderLanes) { - if (enableLazyContextPropagation) { - var currentSourceFiber = sourceFiber.alternate; + workInProgress.flags |= PerformedWork; + reconcileChildren(current, workInProgress, newChildren, renderLanes); + return workInProgress.child; +} - if (currentSourceFiber !== null) { - // Since we never visited the children of the suspended component, we - // need to propagate the context change now, to ensure that we visit - // them during the retry. - // - // We don't have to do this for errors because we retry errors without - // committing in between. So this is specific to Suspense. - propagateParentContextChangesToDeferredTree( - currentSourceFiber, - sourceFiber, - rootRenderLanes - ); - } - } // Reset the memoizedState to what it was before we attempted to render it. - // A legacy mode Suspense quirk, only relevant to hook components. +function updateScopeComponent(current, workInProgress, renderLanes) { + var nextProps = workInProgress.pendingProps; + var nextChildren = nextProps.children; + reconcileChildren(current, workInProgress, nextChildren, renderLanes); + return workInProgress.child; +} - var tag = sourceFiber.tag; +function markWorkInProgressReceivedUpdate() { + didReceiveUpdate = true; +} +function checkIfWorkInProgressReceivedUpdate() { + return didReceiveUpdate; +} - if ( - (sourceFiber.mode & ConcurrentMode) === NoMode && - (tag === FunctionComponent || - tag === ForwardRef || - tag === SimpleMemoComponent) - ) { - var currentSource = sourceFiber.alternate; +function resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress) { + if ((workInProgress.mode & ConcurrentMode) === NoMode) { + if (current !== null) { + // A 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 - if (currentSource) { - sourceFiber.updateQueue = currentSource.updateQueue; - sourceFiber.memoizedState = currentSource.memoizedState; - sourceFiber.lanes = currentSource.lanes; - } else { - sourceFiber.updateQueue = null; - sourceFiber.memoizedState = null; + workInProgress.flags |= Placement; } } } -function markSuspenseBoundaryShouldCapture( - suspenseBoundary, - returnFiber, - sourceFiber, - root, - rootRenderLanes -) { - // This marks a Suspense boundary so that when we're unwinding the stack, - // it captures the suspended "exception" and does a second (fallback) pass. - if ((suspenseBoundary.mode & ConcurrentMode) === NoMode) { - // Legacy Mode Suspense - // - // If the boundary is in legacy mode, we should *not* - // suspend the commit. Pretend as if the suspended component rendered - // null and keep rendering. When the Suspense boundary completes, - // we'll do a second pass to render the fallback. - if (suspenseBoundary === returnFiber) { - // Special case where we suspended while reconciling the children of - // a Suspense boundary's inner Offscreen wrapper fiber. This happens - // when a React.lazy component is a direct child of a - // Suspense boundary. - // - // Suspense boundaries are implemented as multiple fibers, but they - // are a single conceptual unit. The legacy mode behavior where we - // pretend the suspended fiber committed as `null` won't work, - // because in this case the "suspended" fiber is the inner - // Offscreen wrapper. - // - // Because the contents of the boundary haven't started rendering - // yet (i.e. nothing in the tree has partially rendered) we can - // switch to the regular, concurrent mode behavior: mark the - // boundary with ShouldCapture and enter the unwind phase. - suspenseBoundary.flags |= ShouldCapture; - } else { - suspenseBoundary.flags |= DidCapture; - sourceFiber.flags |= ForceUpdateForLegacySuspense; // 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. +function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) { + if (current !== null) { + // Reuse previous dependencies + workInProgress.dependencies = current.dependencies; + } - sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete); + { + // Don't update "base" render times for bailouts. + stopProfilerTimerIfRunning(); + } - if (sourceFiber.tag === ClassComponent) { - var currentSourceFiber = sourceFiber.alternate; + markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. - 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 update to - // prevent a bail out. - var update = createUpdate(SyncLane); - update.tag = ForceUpdate; - enqueueUpdate(sourceFiber, update, SyncLane); - } - } // The source fiber did not complete. Mark it with Sync priority to - // indicate that it still has pending work. + if (!includesSomeLane(renderLanes, workInProgress.childLanes)) { + // 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. + if (enableLazyContextPropagation && current !== null) { + // Before bailing out, check if there are any context changes in + // the children. + lazilyPropagateParentContextChanges(current, workInProgress, renderLanes); - sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane); + if (!includesSomeLane(renderLanes, workInProgress.childLanes)) { + return null; + } + } else { + return null; } + } // This fiber doesn't have work, but its subtree does. Clone the child + // fibers and continue. - return suspenseBoundary; - } // Confirmed that the boundary is in a concurrent mode tree. Continue - // with the normal suspend path. - // - // After this we'll use a set of heuristics to determine whether this - // render pass will run to completion or restart or "suspend" the commit. - // The actual logic for this is spread out in different places. - // - // This first principle is that if we're going to suspend when we complete - // a root, then we should also restart if we get an update or ping that - // might unsuspend it, and vice versa. The only reason to suspend is - // because you think you might want to restart before committing. However, - // it doesn't make sense to restart only while in the period we're suspended. - // - // Restarting too aggressively is also not good because it starves out any - // intermediate loading state. So we use heuristics to determine when. - // Suspense Heuristics - // - // If nothing threw a Promise or all the same fallbacks are already showing, - // then don't suspend/restart. - // - // If this is an initial render of a new tree of Suspense boundaries and - // those trigger a fallback, then don't suspend/restart. We want to ensure - // that we can show the initial loading state as quickly as possible. - // - // If we hit a "Delayed" case, such as when we'd switch from content back into - // a fallback, then we should always suspend/restart. Transitions apply - // to this case. If none is defined, JND is used instead. - // - // If we're already showing a fallback and it gets "retried", allowing us to show - // another level, but there's still an inner boundary that would show a fallback, - // then we suspend/restart for 500ms since the last time we showed a fallback - // anywhere in the tree. This effectively throttles progressive loading into a - // consistent train of commits. This also gives us an opportunity to restart to - // get to the completed state slightly earlier. - // - // If there's ambiguity due to batching it's resolved in preference of: - // 1) "delayed", 2) "initial render", 3) "retry". - // - // We want to ensure that a "busy" state doesn't get force committed. We want to - // ensure that new initial loading states can commit as soon as possible. + cloneChildFibers(current, workInProgress); + return workInProgress.child; +} - suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in - // the begin phase to prevent an early bailout. +function remountFiber(current, oldWorkInProgress, newWorkInProgress) { + { + var returnFiber = oldWorkInProgress.return; - suspenseBoundary.lanes = rootRenderLanes; - return suspenseBoundary; -} + if (returnFiber === null) { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error("Cannot swap the root fiber."); + } // Disconnect from the old current. + // It will get deleted. -function throwException( - root, - returnFiber, - sourceFiber, - value, - rootRenderLanes -) { - // The source fiber did not complete. - sourceFiber.flags |= Incomplete; + current.alternate = null; + oldWorkInProgress.alternate = null; // Connect to the new tree. - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, rootRenderLanes); - } - } + newWorkInProgress.index = oldWorkInProgress.index; + newWorkInProgress.sibling = oldWorkInProgress.sibling; + newWorkInProgress.return = oldWorkInProgress.return; + newWorkInProgress.ref = oldWorkInProgress.ref; // Replace the child/sibling pointers above it. - if ( - value !== null && - typeof value === "object" && - typeof value.then === "function" - ) { - // This is a wakeable. The component suspended. - var wakeable = value; - resetSuspendedComponent(sourceFiber, rootRenderLanes); + if (oldWorkInProgress === returnFiber.child) { + returnFiber.child = newWorkInProgress; + } else { + var prevSibling = returnFiber.child; - { - if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) { - markDidThrowWhileHydratingDEV(); - } - } + if (prevSibling === null) { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error("Expected parent to have a child."); + } // $FlowFixMe[incompatible-use] found when upgrading Flow - { - if (enableDebugTracing) { - if (sourceFiber.mode & DebugTracingMode) { - var name = getComponentNameFromFiber(sourceFiber) || "Unknown"; - logComponentSuspended(name, wakeable); + while (prevSibling.sibling !== oldWorkInProgress) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + prevSibling = prevSibling.sibling; + + if (prevSibling === null) { + // eslint-disable-next-line react-internal/prod-error-codes + throw new Error("Expected to find the previous sibling."); } - } - } // Mark the nearest Suspense boundary to switch to rendering a fallback. + } // $FlowFixMe[incompatible-use] found when upgrading Flow - var suspenseBoundary = getSuspenseHandler(); + prevSibling.sibling = newWorkInProgress; + } // Delete the old fiber and place the new one. + // Since the old fiber is disconnected, we have to schedule it manually. - if (suspenseBoundary !== null) { - switch (suspenseBoundary.tag) { - case SuspenseComponent: { - // If this suspense boundary is not already showing a fallback, mark - // the in-progress render as suspended. We try to perform this logic - // as soon as soon as possible during the render phase, so the work - // loop can know things like whether it's OK to switch to other tasks, - // or whether it can wait for data to resolve before continuing. - // TODO: Most of these checks are already performed when entering a - // Suspense boundary. We should track the information on the stack so - // we don't have to recompute it on demand. This would also allow us - // to unify with `use` which needs to perform this logic even sooner, - // before `throwException` is called. - if (sourceFiber.mode & ConcurrentMode) { - if (getShellBoundary() === null) { - // Suspended in the "shell" of the app. This is an undesirable - // loading state. We should avoid committing this tree. - renderDidSuspendDelayIfPossible(); - } else { - // If we suspended deeper than the shell, we don't need to delay - // the commmit. However, we still call renderDidSuspend if this is - // a new boundary, to tell the work loop that a new fallback has - // appeared during this render. - // TODO: Theoretically we should be able to delete this branch. - // It's currently used for two things: 1) to throttle the - // appearance of successive loading states, and 2) in - // SuspenseList, to determine whether the children include any - // pending fallbacks. For 1, we should apply throttling to all - // retries, not just ones that render an additional fallback. For - // 2, we should check subtreeFlags instead. Then we can delete - // this branch. - var current = suspenseBoundary.alternate; + var deletions = returnFiber.deletions; - if (current === null) { - renderDidSuspend(); - } - } - } + if (deletions === null) { + returnFiber.deletions = [current]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(current); + } - suspenseBoundary.flags &= ~ForceClientRender; - markSuspenseBoundaryShouldCapture( - suspenseBoundary, - returnFiber, - sourceFiber, - root, - rootRenderLanes - ); // Retry listener - // - // If the fallback does commit, we need to attach a different type of - // listener. This one schedules an update on the Suspense boundary to - // turn the fallback state off. - // - // Stash the wakeable on the boundary fiber so we can access it in the - // commit phase. - // - // When the wakeable resolves, we'll attempt to render the boundary - // again ("retry"). + newWorkInProgress.flags |= Placement; // Restart work from the new fiber. - var wakeables = suspenseBoundary.updateQueue; + return newWorkInProgress; + } +} - if (wakeables === null) { - suspenseBoundary.updateQueue = new Set([wakeable]); - } else { - wakeables.add(wakeable); - } +function checkScheduledUpdateOrContext(current, renderLanes) { + // Before performing an early bailout, we must check if there are pending + // updates or context. + var updateLanes = current.lanes; - break; - } + if (includesSomeLane(updateLanes, renderLanes)) { + return true; + } // No pending update, but because context is propagated lazily, we need + // to check for a context change before we bail out. - case OffscreenComponent: { - if (suspenseBoundary.mode & ConcurrentMode) { - suspenseBoundary.flags |= ShouldCapture; - var offscreenQueue = suspenseBoundary.updateQueue; + if (enableLazyContextPropagation) { + var dependencies = current.dependencies; - if (offscreenQueue === null) { - var newOffscreenQueue = { - transitions: null, - markerInstances: null, - wakeables: new Set([wakeable]) - }; - suspenseBoundary.updateQueue = newOffscreenQueue; - } else { - var _wakeables = offscreenQueue.wakeables; + if (dependencies !== null && checkIfContextChanged(dependencies)) { + return true; + } + } - if (_wakeables === null) { - offscreenQueue.wakeables = new Set([wakeable]); - } else { - _wakeables.add(wakeable); - } - } + return false; +} - break; - } - } - // eslint-disable-next-line no-fallthrough +function attemptEarlyBailoutIfNoScheduledUpdate( + current, + workInProgress, + renderLanes +) { + // 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); + pushRootTransition(workInProgress); - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - suspenseBoundary.tag + - "). This " + - "is a bug in React." - ); - } - } // We only attach ping listeners in concurrent mode. Legacy Suspense always - // commits fallbacks synchronously, so there are no pings. + if (enableTransitionTracing) { + pushRootMarkerInstance(workInProgress); + } - if (suspenseBoundary.mode & ConcurrentMode) { - attachPingListener(root, wakeable, rootRenderLanes); + { + var cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, cache); } - return; - } else { - // No boundary was found. Unless this is a sync update, this is OK. - // We can suspend and wait for more data to arrive. - if (root.tag === ConcurrentRoot) { - // In a concurrent root, suspending without a Suspense boundary is - // allowed. It will suspend indefinitely without committing. - // - // TODO: Should we have different behavior for discrete updates? What - // about flushSync? Maybe it should put the tree into an inert state, - // and potentially log a warning. Revisit this for a future release. - attachPingListener(root, wakeable, rootRenderLanes); - renderDidSuspendDelayIfPossible(); - return; - } else { - // In a legacy root, suspending without a boundary is always an error. - var uncaughtSuspenseError = new Error( - "A component suspended while responding to synchronous input. This " + - "will cause the UI to be replaced with a loading indicator. To " + - "fix, updates that suspend should be wrapped " + - "with startTransition." - ); - value = uncaughtSuspenseError; + resetHydrationState(); + break; + + case HostSingleton: + 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; + var context = workInProgress.type._context; + pushProvider(workInProgress, context, newValue); + break; } - } else { - // This is a regular error, not a Suspense wakeable. - if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) { - markDidThrowWhileHydratingDEV(); - var _suspenseBoundary = getSuspenseHandler(); // If the error was thrown during hydration, we may be able to recover by - // discarding the dehydrated content and switching to a client render. - // Instead of surfacing the error, find the nearest Suspense boundary - // and render it again without hydration. + case Profiler: + { + // Profiler should only call onRender when one of its descendants actually rendered. + var hasChildWork = includesSomeLane( + renderLanes, + workInProgress.childLanes + ); - if (_suspenseBoundary !== null) { - if ((_suspenseBoundary.flags & ShouldCapture) === NoFlags$1) { - // Set a flag to indicate that we should try rendering the normal - // children again, not the fallback. - _suspenseBoundary.flags |= ForceClientRender; + if (hasChildWork) { + workInProgress.flags |= Update; } - markSuspenseBoundaryShouldCapture( - _suspenseBoundary, - returnFiber, - sourceFiber, - root, - rootRenderLanes - ); // Even though the user may not be affected by this error, we should - // still log it so it can be fixed. - - queueHydrationError(createCapturedValueAtFiber(value, sourceFiber)); - return; + { + // Reset effect durations for the next eventual effect phase. + // These are reset during render to allow the DevTools commit hook a chance to read them, + var stateNode = workInProgress.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } } - } - } - value = createCapturedValueAtFiber(value, sourceFiber); - renderDidError(value); // 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. + break; - var workInProgress = returnFiber; + case SuspenseComponent: { + var state = workInProgress.memoizedState; - do { - switch (workInProgress.tag) { - case HostRoot: { - var _errorInfo = value; - workInProgress.flags |= ShouldCapture; - var lane = pickArbitraryLane(rootRenderLanes); - workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); - var update = createRootErrorUpdate(workInProgress, _errorInfo, lane); - enqueueCapturedUpdate(workInProgress, update); - return; - } + if (state !== null) { + if (state.dehydrated !== null) { + // We're not going to render the children, so this is just to maintain + // push/pop symmetry + pushPrimaryTreeSuspenseHandler(workInProgress); // We know that this component will suspend again because if it has + // been unsuspended it has committed as a resolved Suspense component. + // If it needs to be retried, it should have work scheduled on it. - case ClassComponent: - // Capture and retry - var errorInfo = value; - var ctor = workInProgress.type; - var instance = workInProgress.stateNode; + workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we + // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. - if ( - (workInProgress.flags & DidCapture) === NoFlags$1 && - (typeof ctor.getDerivedStateFromError === "function" || - (instance !== null && - typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance))) - ) { - workInProgress.flags |= ShouldCapture; + return null; + } // 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 + // child fragment. - var _lane = pickArbitraryLane(rootRenderLanes); + var primaryChildFragment = workInProgress.child; + var primaryChildLanes = primaryChildFragment.childLanes; - workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); // Schedule the error boundary to re-render using updated state + if (includesSomeLane(renderLanes, primaryChildLanes)) { + // The primary children have pending work. Use the normal path + // to attempt to render the primary children again. + return updateSuspenseComponent(current, workInProgress, renderLanes); + } else { + // The primary child fragment does not have pending work marked + // on it + pushPrimaryTreeSuspenseHandler(workInProgress); // The primary children do not have pending work with sufficient + // priority. Bailout. - var _update = createClassErrorUpdate( + var child = bailoutOnAlreadyFinishedWork( + current, workInProgress, - errorInfo, - _lane + renderLanes ); - enqueueCapturedUpdate(workInProgress, _update); - return; + if (child !== null) { + // The fallback children have pending work. Skip over the + // primary children and work on the fallback. + return child.sibling; + } else { + // Note: We can return `null` here because we already checked + // whether there were nested context consumers, via the call to + // `bailoutOnAlreadyFinishedWork` above. + return null; + } } + } else { + pushPrimaryTreeSuspenseHandler(workInProgress); + } - break; - } // $FlowFixMe[incompatible-type] we bail out when we get a null + break; + } - workInProgress = workInProgress.return; - } while (workInProgress !== null); -} + case SuspenseListComponent: { + var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; -var TransitionRoot = 0; -var TransitionTracingMarker = 1; -function processTransitionCallbacks(pendingTransitions, endTime, callbacks) { - if (enableTransitionTracing) { - if (pendingTransitions !== null) { - var transitionStart = pendingTransitions.transitionStart; - var onTransitionStart = callbacks.onTransitionStart; + var _hasChildWork = includesSomeLane( + renderLanes, + workInProgress.childLanes + ); - if (transitionStart !== null && onTransitionStart != null) { - transitionStart.forEach(function (transition) { - return onTransitionStart(transition.name, transition.startTime); - }); + if (enableLazyContextPropagation && !_hasChildWork) { + // Context changes may not have been propagated yet. We need to do + // that now, before we can decide whether to bail out. + // TODO: We use `childLanes` as a heuristic for whether there is + // remaining work in a few places, including + // `bailoutOnAlreadyFinishedWork` and + // `updateDehydratedSuspenseComponent`. We should maybe extract this + // into a dedicated function. + lazilyPropagateParentContextChanges( + current, + workInProgress, + renderLanes + ); + _hasChildWork = includesSomeLane( + renderLanes, + workInProgress.childLanes + ); } - var markerProgress = pendingTransitions.markerProgress; - var onMarkerProgress = callbacks.onMarkerProgress; + if (didSuspendBefore) { + if (_hasChildWork) { + // If something was in fallback state last time, and we have all the + // same children then we're still in progressive loading state. + // Something might get unblocked by state updates or retries in the + // tree which will affect the tail. So we need to use the normal + // path to compute the correct tail. + return updateSuspenseListComponent( + current, + workInProgress, + renderLanes + ); + } // If none of the children had any work, that means that none of + // them got retried so they'll still be blocked in the same way + // as before. We can fast bail out. - if (onMarkerProgress != null && markerProgress !== null) { - markerProgress.forEach(function (markerInstance, markerName) { - if (markerInstance.transitions !== null) { - // TODO: Clone the suspense object so users can't modify it - var pending = - markerInstance.pendingBoundaries !== null - ? Array.from(markerInstance.pendingBoundaries.values()) - : []; - markerInstance.transitions.forEach(function (transition) { - onMarkerProgress( - transition.name, - markerName, - transition.startTime, - endTime, - pending - ); - }); - } - }); - } + workInProgress.flags |= DidCapture; + } // If nothing suspended before and we're rendering the same children, + // then the tail doesn't matter. Anything new that suspends will work + // in the "together" mode, so we can continue from the state we had. - var markerComplete = pendingTransitions.markerComplete; - var onMarkerComplete = callbacks.onMarkerComplete; + var renderState = workInProgress.memoizedState; - if (markerComplete !== null && onMarkerComplete != null) { - markerComplete.forEach(function (transitions, markerName) { - transitions.forEach(function (transition) { - onMarkerComplete( - transition.name, - markerName, - transition.startTime, - endTime - ); - }); - }); + if (renderState !== null) { + // Reset to the "together" mode in case we've started a different + // update in the past but didn't complete it. + renderState.rendering = null; + renderState.tail = null; + renderState.lastEffect = null; } - var markerIncomplete = pendingTransitions.markerIncomplete; - var onMarkerIncomplete = callbacks.onMarkerIncomplete; - - if (onMarkerIncomplete != null && markerIncomplete !== null) { - markerIncomplete.forEach(function (_ref, markerName) { - var transitions = _ref.transitions, - aborts = _ref.aborts; - transitions.forEach(function (transition) { - var filteredAborts = []; - aborts.forEach(function (abort) { - switch (abort.reason) { - case "marker": { - filteredAborts.push({ - type: "marker", - name: abort.name, - endTime: endTime - }); - break; - } - - case "suspense": { - filteredAborts.push({ - type: "suspense", - name: abort.name, - endTime: endTime - }); - break; - } - } - }); + pushSuspenseListContext(workInProgress, suspenseStackCursor.current); - if (filteredAborts.length > 0) { - onMarkerIncomplete( - transition.name, - markerName, - transition.startTime, - filteredAborts - ); - } - }); - }); + if (_hasChildWork) { + break; + } else { + // If none of the children had any work, that means that none of + // them got retried so they'll still be blocked in the same way + // as before. We can fast bail out. + return null; } + } - var transitionProgress = pendingTransitions.transitionProgress; - var onTransitionProgress = callbacks.onTransitionProgress; + case OffscreenComponent: + case LegacyHiddenComponent: { + // Need to check if the tree still needs to be deferred. This is + // almost identical to the logic used in the normal update path, + // so we'll just enter that. The only difference is we'll bail out + // at the next level instead of this one, because the child props + // have not changed. Which is fine. + // TODO: Probably should refactor `beginWork` to split the bailout + // path from the normal path. I'm tempted to do a labeled break here + // but I won't :) + workInProgress.lanes = NoLanes; + return updateOffscreenComponent(current, workInProgress, renderLanes); + } - if (onTransitionProgress != null && transitionProgress !== null) { - transitionProgress.forEach(function (pending, transition) { - onTransitionProgress( - transition.name, - transition.startTime, - endTime, - Array.from(pending.values()) - ); - }); + case CacheComponent: { + { + var _cache = current.memoizedState.cache; + pushCacheProvider(workInProgress, _cache); } - var transitionComplete = pendingTransitions.transitionComplete; - var onTransitionComplete = callbacks.onTransitionComplete; + break; + } - if (transitionComplete !== null && onTransitionComplete != null) { - transitionComplete.forEach(function (transition) { - return onTransitionComplete( - transition.name, - transition.startTime, - endTime - ); - }); + case TracingMarkerComponent: { + if (enableTransitionTracing) { + var instance = workInProgress.stateNode; + + if (instance !== null) { + pushMarkerInstance(workInProgress, instance); + } } } } -} // For every tracing marker, store a pointer to it. We will later access it -// to get the set of suspense boundaries that need to resolve before the -// tracing marker can be logged as complete -// This code lives separate from the ReactFiberTransition code because -// we push and pop on the tracing marker, not the suspense boundary -var markerInstanceStack = createCursor(null); -function pushRootMarkerInstance(workInProgress) { - if (enableTransitionTracing) { - // On the root, every transition gets mapped to it's own map of - // suspense boundaries. The transition is marked as complete when - // the suspense boundaries map is empty. We do this because every - // transition completes at different times and depends on different - // suspense boundaries to complete. We store all the transitions - // along with its map of suspense boundaries in the root incomplete - // transitions map. Each entry in this map functions like a tracing - // marker does, so we can push it onto the marker instance stack - var transitions = getWorkInProgressTransitions(); - var root = workInProgress.stateNode; + return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); +} - if (transitions !== null) { - transitions.forEach(function (transition) { - if (!root.incompleteTransitions.has(transition)) { - var markerInstance = { - tag: TransitionRoot, - transitions: new Set([transition]), - pendingBoundaries: null, - aborts: null, - name: null - }; - root.incompleteTransitions.set(transition, markerInstance); - } - }); +function beginWork$1(current, workInProgress, renderLanes) { + { + if (workInProgress._debugNeedsRemount && current !== null) { + // This will restart the begin phase with a new fiber. + return remountFiber( + current, + workInProgress, + createFiberFromTypeAndProps( + workInProgress.type, + workInProgress.key, + workInProgress.pendingProps, + workInProgress._debugOwner || null, + workInProgress.mode, + workInProgress.lanes + ) + ); } + } - var markerInstances = []; // For ever transition on the suspense boundary, we push the transition - // along with its map of pending suspense boundaries onto the marker - // instance stack. + if (current !== null) { + var oldProps = current.memoizedProps; + var newProps = workInProgress.pendingProps; - root.incompleteTransitions.forEach(function (markerInstance) { - markerInstances.push(markerInstance); - }); - push(markerInstanceStack, markerInstances, workInProgress); - } -} -function popRootMarkerInstance(workInProgress) { - if (enableTransitionTracing) { - pop(markerInstanceStack, workInProgress); - } -} -function pushMarkerInstance(workInProgress, markerInstance) { - if (enableTransitionTracing) { - if (markerInstanceStack.current === null) { - push(markerInstanceStack, [markerInstance], workInProgress); + if ( + oldProps !== newProps || + hasContextChanged() || // Force a re-render if the implementation changed due to hot reload: + workInProgress.type !== current.type + ) { + // 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 { - push( - markerInstanceStack, - markerInstanceStack.current.concat(markerInstance), - workInProgress + // Neither props nor legacy context changes. Check if there's a pending + // update or context change. + var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( + current, + renderLanes + ); + + if ( + !hasScheduledUpdateOrContext && // If this is the second pass of an error or suspense boundary, there + // may not be work scheduled on `current`, so we check for this flag. + (workInProgress.flags & DidCapture) === NoFlags$1 + ) { + // No pending updates or context. Bail out now. + didReceiveUpdate = false; + return attemptEarlyBailoutIfNoScheduledUpdate( + current, + workInProgress, + renderLanes + ); + } + + if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { + // This is a special case that only exists for legacy mode. + // See https://github.com/facebook/react/pull/19216. + didReceiveUpdate = true; + } else { + // An update was scheduled on this fiber, but there are no new props + // nor legacy context. Set this to false. If an update queue or context + // consumer produces a changed value, it will set this to true. Otherwise, + // the component will assume the children have not changed and bail out. + didReceiveUpdate = false; + } + } + } else { + didReceiveUpdate = false; + + if (getIsHydrating() && isForkedChild(workInProgress)) { + // Check if this child belongs to a list of muliple children in + // its parent. + // + // In a true multi-threaded implementation, we would render children on + // parallel threads. This would represent the beginning of a new render + // thread for this subtree. + // + // We only use this for id generation during hydration, which is why the + // logic is located in this special branch. + var slotIndex = workInProgress.index; + var numberOfForks = getForksAtLevel(); + pushTreeId(workInProgress, numberOfForks, slotIndex); + } + } // Before entering the begin phase, clear pending update priority. + // TODO: This assumes that we're about to evaluate the component and process + // the update queue. However, there's an exception: SimpleMemoComponent + // sometimes bails out later in the begin phase. This indicates that we should + // move this assignment out of the common path and into each branch. + + workInProgress.lanes = NoLanes; + + switch (workInProgress.tag) { + case IndeterminateComponent: { + return mountIndeterminateComponent( + current, + workInProgress, + workInProgress.type, + renderLanes + ); + } + + case LazyComponent: { + var elementType = workInProgress.elementType; + return mountLazyComponent( + current, + workInProgress, + elementType, + renderLanes + ); + } + + case FunctionComponent: { + var Component = workInProgress.type; + var unresolvedProps = workInProgress.pendingProps; + var resolvedProps = + workInProgress.elementType === Component + ? unresolvedProps + : resolveDefaultProps(Component, unresolvedProps); + return updateFunctionComponent( + current, + workInProgress, + Component, + resolvedProps, + renderLanes + ); + } + + case ClassComponent: { + var _Component = workInProgress.type; + var _unresolvedProps = workInProgress.pendingProps; + + var _resolvedProps = + workInProgress.elementType === _Component + ? _unresolvedProps + : resolveDefaultProps(_Component, _unresolvedProps); + + return updateClassComponent( + current, + workInProgress, + _Component, + _resolvedProps, + renderLanes ); } - } -} -function popMarkerInstance(workInProgress) { - if (enableTransitionTracing) { - pop(markerInstanceStack, workInProgress); - } -} -function getMarkerInstances() { - if (enableTransitionTracing) { - return markerInstanceStack.current; - } - return null; -} + case HostRoot: + return updateHostRoot(current, workInProgress, renderLanes); -var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows -// into a dehydrated boundary. + case HostHoistable: { + return updateHostHoistable(current, workInProgress); + } -var SelectiveHydrationException = new Error( - "This is not a real error. It's an implementation detail of React's " + - "selective hydration feature. If this leaks into userspace, it's a bug in " + - "React. Please file an issue." -); -var didReceiveUpdate = false; -var didWarnAboutBadClass; -var didWarnAboutModulePatternComponent; -var didWarnAboutContextTypeOnFunctionComponent; -var didWarnAboutGetDerivedStateOnFunctionComponent; -var didWarnAboutFunctionRefs; -var didWarnAboutReassigningProps; -var didWarnAboutRevealOrder; -var didWarnAboutTailOptions; -var didWarnAboutDefaultPropsOnFunctionComponent; + // eslint-disable-next-line no-fallthrough -{ - didWarnAboutBadClass = {}; - didWarnAboutModulePatternComponent = {}; - didWarnAboutContextTypeOnFunctionComponent = {}; - didWarnAboutGetDerivedStateOnFunctionComponent = {}; - didWarnAboutFunctionRefs = {}; - didWarnAboutReassigningProps = false; - didWarnAboutRevealOrder = {}; - didWarnAboutTailOptions = {}; - didWarnAboutDefaultPropsOnFunctionComponent = {}; -} + case HostSingleton: { + return updateHostSingleton(current, workInProgress, renderLanes); + } -function reconcileChildren(current, workInProgress, nextChildren, renderLanes) { - if (current === 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, - renderLanes - ); - } 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.child, - nextChildren, - renderLanes - ); - } -} + // eslint-disable-next-line no-fallthrough -function forceUnmountCurrentAndReconcile( - current, - workInProgress, - nextChildren, - renderLanes -) { - // 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.child, - null, - renderLanes - ); // 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 - // identities match. + case HostComponent: + return updateHostComponent$1(current, workInProgress, renderLanes); - workInProgress.child = reconcileChildFibers( - workInProgress, - null, - nextChildren, - renderLanes - ); -} + case HostText: + return updateHostText$1(current, workInProgress); -function updateForwardRef( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { - // 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. - { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var innerPropTypes = Component.propTypes; + case SuspenseComponent: + return updateSuspenseComponent(current, workInProgress, renderLanes); - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(Component) - ); - } - } - } + case HostPortal: + return updatePortalComponent(current, workInProgress, renderLanes); - var render = Component.render; - var ref = workInProgress.ref; // The rest is a fork of updateFunctionComponent + case ForwardRef: { + var type = workInProgress.type; + var _unresolvedProps2 = workInProgress.pendingProps; - var nextChildren; - var hasId; - prepareToReadContext(workInProgress, renderLanes); + var _resolvedProps2 = + workInProgress.elementType === type + ? _unresolvedProps2 + : resolveDefaultProps(type, _unresolvedProps2); - if (enableSchedulingProfiler) { - markComponentRenderStarted(workInProgress); - } + return updateForwardRef( + current, + workInProgress, + type, + _resolvedProps2, + renderLanes + ); + } - { - ReactCurrentOwner$2.current = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, - workInProgress, - render, - nextProps, - ref, - renderLanes - ); - hasId = checkDidRenderIdHook(); - setIsRendering(false); - } + case Fragment: + return updateFragment(current, workInProgress, renderLanes); - if (enableSchedulingProfiler) { - markComponentRenderStopped(); - } + case Mode: + return updateMode(current, workInProgress, renderLanes); - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); - } + case Profiler: + return updateProfiler(current, workInProgress, renderLanes); - if (getIsHydrating() && hasId) { - pushMaterializedTreeId(workInProgress); - } // React DevTools reads this flag. + case ContextProvider: + return updateContextProvider(current, workInProgress, renderLanes); - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + case ContextConsumer: + return updateContextConsumer(current, workInProgress, renderLanes); -function updateMemoComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { - if (current === null) { - var type = Component.type; + case MemoComponent: { + var _type2 = workInProgress.type; + var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. - if ( - isSimpleFunctionComponent(type) && - Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either. - Component.defaultProps === undefined - ) { - var resolvedType = type; + var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); { - resolvedType = resolveFunctionForHotReloading(type); - } // 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 = resolvedType; + if (workInProgress.type !== workInProgress.elementType) { + var outerPropTypes = _type2.propTypes; - { - validateFunctionComponentInDev(workInProgress, type); + if (outerPropTypes) { + checkPropTypes( + outerPropTypes, + _resolvedProps3, // Resolved for outer only + "prop", + getComponentNameFromType(_type2) + ); + } + } } + _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); + return updateMemoComponent( + current, + workInProgress, + _type2, + _resolvedProps3, + renderLanes + ); + } + + case SimpleMemoComponent: { return updateSimpleMemoComponent( current, workInProgress, - resolvedType, - nextProps, + workInProgress.type, + workInProgress.pendingProps, renderLanes ); } - { - var innerPropTypes = type.propTypes; + case IncompleteClassComponent: { + var _Component2 = workInProgress.type; + var _unresolvedProps4 = workInProgress.pendingProps; - if (innerPropTypes) { - // Inner memo component props aren't currently validated in createElement. - // We could move it there, but we'd still need this for lazy code path. - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(type) - ); - } + var _resolvedProps4 = + workInProgress.elementType === _Component2 + ? _unresolvedProps4 + : resolveDefaultProps(_Component2, _unresolvedProps4); - if (Component.defaultProps !== undefined) { - var componentName = getComponentNameFromType(type) || "Unknown"; + return mountIncompleteClassComponent( + current, + workInProgress, + _Component2, + _resolvedProps4, + renderLanes + ); + } - if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { - error( - "%s: Support for defaultProps will be removed from memo components " + - "in a future major release. Use JavaScript default parameters instead.", - componentName - ); + case SuspenseListComponent: { + return updateSuspenseListComponent(current, workInProgress, renderLanes); + } - didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; - } + case ScopeComponent: { + { + return updateScopeComponent(current, workInProgress, renderLanes); } } - var child = createFiberFromTypeAndProps( - Component.type, - null, - nextProps, - workInProgress, - workInProgress.mode, - renderLanes - ); - child.ref = workInProgress.ref; - child.return = workInProgress; - workInProgress.child = child; - return child; - } - - { - var _type = Component.type; - var _innerPropTypes = _type.propTypes; - - if (_innerPropTypes) { - // Inner memo component props aren't currently validated in createElement. - // We could move it there, but we'd still need this for lazy code path. - checkPropTypes( - _innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(_type) - ); + case OffscreenComponent: { + return updateOffscreenComponent(current, workInProgress, renderLanes); } - } - - var currentChild = current.child; // This is always exactly one child - var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( - current, - renderLanes - ); + case LegacyHiddenComponent: { + { + return updateLegacyHiddenComponent( + current, + workInProgress, + renderLanes + ); + } + } - if (!hasScheduledUpdateOrContext) { - // 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 + case CacheComponent: { + { + return updateCacheComponent(current, workInProgress, renderLanes); + } + } - var compare = Component.compare; - compare = compare !== null ? compare : shallowEqual; + case TracingMarkerComponent: { + if (enableTransitionTracing) { + return updateTracingMarkerComponent( + current, + workInProgress, + renderLanes + ); + } - if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) { - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + break; } - } // React DevTools reads this flag. + } - workInProgress.flags |= PerformedWork; - var newChild = createWorkInProgress(currentChild, nextProps); - newChild.ref = workInProgress.ref; - newChild.return = workInProgress; - workInProgress.child = newChild; - return newChild; + throw new Error( + "Unknown unit of work tag (" + + workInProgress.tag + + "). This error is likely caused by a bug in " + + "React. Please file an issue." + ); } -function updateSimpleMemoComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { - // 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 (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var outerMemoType = workInProgress.elementType; - - if (outerMemoType.$$typeof === REACT_LAZY_TYPE) { - // We warn when you define propTypes on lazy() - // so let's just skip over it to find memo() outer wrapper. - // Inner props for memo are validated later. - var lazyComponent = outerMemoType; - var payload = lazyComponent._payload; - var init = lazyComponent._init; - - try { - outerMemoType = init(payload); - } catch (x) { - outerMemoType = null; - } // Inner propTypes will be validated in the function component path. +var valueCursor = createCursor(null); +var rendererCursorDEV; - var outerPropTypes = outerMemoType && outerMemoType.propTypes; +{ + rendererCursorDEV = createCursor(null); +} - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - nextProps, // Resolved (SimpleMemoComponent has no defaultProps) - "prop", - getComponentNameFromType(outerMemoType) - ); - } - } - } - } +var rendererSigil; - if (current !== null) { - var prevProps = current.memoizedProps; +{ + // Use this to detect multiple renderers using the same context + rendererSigil = {}; +} - if ( - shallowEqual(prevProps, nextProps) && - current.ref === workInProgress.ref && // Prevent bailout if the implementation changed due to hot reload. - workInProgress.type === current.type - ) { - didReceiveUpdate = false; // The props are shallowly equal. Reuse the previous props object, like we - // would during a normal fiber bailout. - // - // We don't have strong guarantees that the props object is referentially - // equal during updates where we can't bail out anyway — like if the props - // are shallowly equal, but there's a local state or context update in the - // same batch. - // - // However, as a principle, we should aim to make the behavior consistent - // across different ways of memoizing a component. For example, React.memo - // has a different internal Fiber layout if you pass a normal function - // component (SimpleMemoComponent) versus if you pass a different type - // like forwardRef (MemoComponent). But this is an implementation detail. - // Wrapping a component in forwardRef (or React.lazy, etc) shouldn't - // affect whether the props object is reused during a bailout. +var currentlyRenderingFiber = null; +var lastContextDependency = null; +var lastFullyObservedContext = null; +var isDisallowedContextReadInDEV = false; +function resetContextDependencies() { + // This is called right before React yields execution, to ensure `readContext` + // cannot be called outside the render phase. + currentlyRenderingFiber = null; + lastContextDependency = null; + lastFullyObservedContext = null; - workInProgress.pendingProps = nextProps = prevProps; + { + isDisallowedContextReadInDEV = false; + } +} +function enterDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = true; + } +} +function exitDisallowedContextReadInDEV() { + { + isDisallowedContextReadInDEV = false; + } +} +function pushProvider(providerFiber, context, nextValue) { + { + push(valueCursor, context._currentValue, providerFiber); + context._currentValue = nextValue; - if (!checkScheduledUpdateOrContext(current, renderLanes)) { - // The pending lanes were cleared at the beginning of beginWork. We're - // about to bail out, but there might be other lanes that weren't - // included in the current render. Usually, the priority level of the - // remaining updates is accumulated during the evaluation of the - // component (i.e. when processing the update queue). But since since - // we're bailing out early *without* evaluating the component, we need - // to account for it here, too. Reset to the value of the current fiber. - // NOTE: This only applies to SimpleMemoComponent, not MemoComponent, - // because a MemoComponent fiber does not have hooks or an update queue; - // rather, it wraps around an inner component, which may or may not - // contains hooks. - // TODO: Move the reset at in beginWork out of the common path so that - // this is no longer necessary. - workInProgress.lanes = current.lanes; - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes + { + push(rendererCursorDEV, context._currentRenderer, providerFiber); + + if ( + context._currentRenderer !== undefined && + context._currentRenderer !== null && + context._currentRenderer !== rendererSigil + ) { + error( + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." ); - } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { - // This is a special case that only exists for legacy mode. - // See https://github.com/facebook/react/pull/19216. - didReceiveUpdate = true; } + + context._currentRenderer = rendererSigil; } } - - return updateFunctionComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes - ); } +function popProvider(context, providerFiber) { + var currentValue = valueCursor.current; -function updateOffscreenComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - var nextIsDetached = - (workInProgress.stateNode._pendingVisibility & OffscreenDetached) !== 0; - var prevState = current !== null ? current.memoizedState : null; - markRef$1(current, workInProgress); - - if ( - nextProps.mode === "hidden" || - nextProps.mode === "unstable-defer-without-hiding" || - nextIsDetached - ) { - // Rendering a hidden tree. - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; + { + if (currentValue === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) { + context._currentValue = context._defaultValue; + } else { + context._currentValue = currentValue; + } - if (didSuspend) { - // Something suspended inside a hidden tree - // Include the base lanes from the last render - var nextBaseLanes = - prevState !== null - ? mergeLanes(prevState.baseLanes, renderLanes) - : renderLanes; + { + var currentRenderer = rendererCursorDEV.current; + pop(rendererCursorDEV, providerFiber); + context._currentRenderer = currentRenderer; + } + } - if (current !== null) { - // Reset to the current children - var currentChild = (workInProgress.child = current.child); // The current render suspended, but there may be other lanes with - // pending work. We can't read `childLanes` from the current Offscreen - // fiber because we reset it when it was deferred; however, we can read - // the pending lanes from the child fibers. + pop(valueCursor, providerFiber); +} +function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) { + // Update the child lanes of all the ancestors, including the alternates. + var node = parent; - var currentChildLanes = NoLanes; + while (node !== null) { + var alternate = node.alternate; - while (currentChild !== null) { - currentChildLanes = mergeLanes( - mergeLanes(currentChildLanes, currentChild.lanes), - currentChild.childLanes - ); - currentChild = currentChild.sibling; - } + if (!isSubsetOfLanes(node.childLanes, renderLanes)) { + node.childLanes = mergeLanes(node.childLanes, renderLanes); - var lanesWeJustAttempted = nextBaseLanes; - var remainingChildLanes = removeLanes( - currentChildLanes, - lanesWeJustAttempted - ); - workInProgress.childLanes = remainingChildLanes; - } else { - workInProgress.childLanes = NoLanes; - workInProgress.child = null; + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); } + } else if ( + alternate !== null && + !isSubsetOfLanes(alternate.childLanes, renderLanes) + ) { + alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + } else; - return deferHiddenOffscreenComponent( - current, - workInProgress, - nextBaseLanes, - renderLanes + if (node === propagationRoot) { + break; + } + + node = node.return; + } + + { + if (node !== propagationRoot) { + error( + "Expected to find the propagation root when scheduling context work. " + + "This error is likely caused by a bug in React. Please file an issue." ); } + } +} +function propagateContextChange(workInProgress, context, renderLanes) { + if (enableLazyContextPropagation) { + // TODO: This path is only used by Cache components. Update + // lazilyPropagateParentContextChanges to look for Cache components so they + // can take advantage of lazy propagation. + var forcePropagateEntireTree = true; + propagateContextChanges( + workInProgress, + [context], + renderLanes, + forcePropagateEntireTree + ); + } else { + propagateContextChange_eager(workInProgress, context, renderLanes); + } +} - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - // In legacy sync mode, don't defer the subtree. Render it now. - // TODO: Consider how Offscreen should work with transitions in the future - var nextState = { - baseLanes: NoLanes, - cachePool: null - }; - workInProgress.memoizedState = nextState; +function propagateContextChange_eager(workInProgress, context, renderLanes) { + // Only used by eager implementation + if (enableLazyContextPropagation) { + return; + } - { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null, null); - } - } + var fiber = workInProgress.child; - reuseHiddenContextOnStack(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); - } else if (!includesSomeLane(renderLanes, OffscreenLane)) { - // We're hidden, and we're not rendering at Offscreen. We will bail out - // and resume this tree later. - // Schedule this fiber to re-render at Offscreen priority - workInProgress.lanes = workInProgress.childLanes = - laneToLanes(OffscreenLane); // Include the base lanes from the last render + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } - var _nextBaseLanes = - prevState !== null - ? mergeLanes(prevState.baseLanes, renderLanes) - : renderLanes; + while (fiber !== null) { + var nextFiber = void 0; // Visit this fiber. - return deferHiddenOffscreenComponent( - current, - workInProgress, - _nextBaseLanes, - renderLanes - ); - } else { - // This is the second render. The surrounding visible content has already - // committed. Now we resume rendering the hidden tree. - // Rendering at offscreen, so we can clear the base lanes. - var _nextState = { - baseLanes: NoLanes, - cachePool: null - }; - workInProgress.memoizedState = _nextState; + var list = fiber.dependencies; - if (current !== null) { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - var prevCachePool = prevState !== null ? prevState.cachePool : null; // TODO: Consider if and how Offscreen pre-rendering should - // be attributed to the transition that spawned it + if (list !== null) { + nextFiber = fiber.child; + var dependency = list.firstContext; - pushTransition(workInProgress, prevCachePool, null); - } // Push the lanes that were skipped when we bailed out. + while (dependency !== null) { + // Check if the context matches. + if (dependency.context === context) { + // Match! Schedule an update on this fiber. + if (fiber.tag === ClassComponent) { + // Schedule a force update on the work-in-progress. + var lane = pickArbitraryLane(renderLanes); + var update = createUpdate(lane); + 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. + // Inlined `enqueueUpdate` to remove interleaved update check - if (prevState !== null) { - pushHiddenContext(workInProgress, prevState); - } else { - reuseHiddenContextOnStack(workInProgress); - } + var updateQueue = fiber.updateQueue; - pushOffscreenSuspenseHandler(workInProgress); - } - } else { - // Rendering a visible tree. - if (prevState !== null) { - // We're going from hidden -> visible. - var _prevCachePool = null; + if (updateQueue === null); + else { + var sharedQueue = updateQueue.shared; + var pending = sharedQueue.pending; - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - _prevCachePool = prevState.cachePool; - } + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - var transitions = null; + sharedQueue.pending = update; + } + } - if (enableTransitionTracing) { - // We have now gone from hidden to visible, so any transitions should - // be added to the stack to get added to any Offscreen/suspense children - var instance = workInProgress.stateNode; + fiber.lanes = mergeLanes(fiber.lanes, renderLanes); + var alternate = fiber.alternate; - if (instance !== null && instance._transitions != null) { - transitions = Array.from(instance._transitions); + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } + + scheduleContextWorkOnParentPath( + fiber.return, + renderLanes, + workInProgress + ); // Mark the updated lanes on the list, too. + + list.lanes = mergeLanes(list.lanes, renderLanes); // 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 (fiber.tag === DehydratedFragment) { + // If a dehydrated suspense boundary 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. + var parentSuspense = fiber.return; - pushTransition(workInProgress, _prevCachePool, transitions); // Push the lanes that were skipped when we bailed out. + if (parentSuspense === null) { + throw new Error( + "We just came from a parent so we must have had a parent. This is a bug in React." + ); + } - pushHiddenContext(workInProgress, prevState); - reuseSuspenseHandlerOnStack(workInProgress); // Since we're not hidden anymore, reset the state + parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); + var _alternate = parentSuspense.alternate; - workInProgress.memoizedState = null; + if (_alternate !== null) { + _alternate.lanes = mergeLanes(_alternate.lanes, renderLanes); + } // 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 childLanes on + // this fiber to indicate that a context has changed. + + scheduleContextWorkOnParentPath( + parentSuspense, + renderLanes, + workInProgress + ); + nextFiber = fiber.sibling; } else { - // We weren't previously hidden, and we still aren't, so there's nothing - // special to do. Need to push to the stack regardless, though, to avoid - // a push/pop misalignment. - { - // If the render that spawned this one accessed the cache pool, resume - // using the same cache. Unless the parent changed, since that means - // there was a refresh. - if (current !== null) { - pushTransition(workInProgress, null, null); + // 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; } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. - reuseHiddenContextOnStack(workInProgress); - reuseSuspenseHandlerOnStack(workInProgress); + 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; + } } - } - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + fiber = nextFiber; + } } -function deferHiddenOffscreenComponent( - current, +function propagateContextChanges( workInProgress, - nextBaseLanes, - renderLanes + contexts, + renderLanes, + forcePropagateEntireTree ) { - var nextState = { - baseLanes: nextBaseLanes, - // Save the cache pool so we can resume later. - cachePool: getOffscreenDeferredCache() - }; - workInProgress.memoizedState = nextState; - - { - // push the cache pool even though we're going to bail out - // because otherwise there'd be a context mismatch - if (current !== null) { - pushTransition(workInProgress, null, null); - } - } // We're about to bail out, but we need to push this to the stack anyway - // to avoid a push/pop misalignment. - - reuseHiddenContextOnStack(workInProgress); - pushOffscreenSuspenseHandler(workInProgress); - - if (enableLazyContextPropagation && current !== null) { - // Since this tree will resume rendering in a separate render, we need - // to propagate parent contexts now so we don't lose track of which - // ones changed. - propagateParentContextChangesToDeferredTree( - current, - workInProgress, - renderLanes - ); + // Only used by lazy implementation + if (!enableLazyContextPropagation) { + return; } - return null; -} // Note: These happen to have identical begin phases, for now. We shouldn't hold -// ourselves to this constraint, though. If the behavior diverges, we should -// fork the function. - -var updateLegacyHiddenComponent = updateOffscreenComponent; + var fiber = workInProgress.child; -function updateCacheComponent(current, workInProgress, renderLanes) { - prepareToReadContext(workInProgress, renderLanes); - var parentCache = readContext(CacheContext); + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber.return = workInProgress; + } - if (current === null) { - // Initial mount. Request a fresh cache from the pool. - var freshCache = requestCacheFromPool(renderLanes); - var initialState = { - parent: parentCache, - cache: freshCache - }; - workInProgress.memoizedState = initialState; - initializeUpdateQueue(workInProgress); - pushCacheProvider(workInProgress, freshCache); - } else { - // Check for updates - if (includesSomeLane(current.lanes, renderLanes)) { - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, null, null, renderLanes); - } + while (fiber !== null) { + var nextFiber = void 0; // Visit this fiber. - var prevState = current.memoizedState; - var nextState = workInProgress.memoizedState; // Compare the new parent cache to the previous to see detect there was - // a refresh. + var list = fiber.dependencies; - if (prevState.parent !== parentCache) { - // Refresh in parent. Update the parent. - var derivedState = { - parent: parentCache, - cache: parentCache - }; // Copied from getDerivedStateFromProps implementation. Once the update - // queue is empty, persist the derived state onto the base state. + if (list !== null) { + nextFiber = fiber.child; + var dep = list.firstContext; - workInProgress.memoizedState = derivedState; + findChangedDep: while (dep !== null) { + // Assigning these to constants to help Flow + var dependency = dep; + var consumer = fiber; - if (workInProgress.lanes === NoLanes) { - var updateQueue = workInProgress.updateQueue; - workInProgress.memoizedState = updateQueue.baseState = derivedState; - } + for (var i = 0; i < contexts.length; i++) { + var context = contexts[i]; // Check if the context matches. + // TODO: Compare selected values to bail out early. - pushCacheProvider(workInProgress, parentCache); // No need to propagate a context change because the refreshed parent - // already did. - } else { - // The parent didn't refresh. Now check if this cache did. - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); + if (dependency.context === context) { + // Match! Schedule an update on this fiber. + // In the lazy implementation, don't mark a dirty flag on the + // dependency itself. Not all changes are propagated, so we can't + // rely on the propagation function alone to determine whether + // something has changed; the consumer will check. In the future, we + // could add back a dirty flag as an optimization to avoid double + // checking, but until we have selectors it's not really worth + // the trouble. + consumer.lanes = mergeLanes(consumer.lanes, renderLanes); + var alternate = consumer.alternate; - if (nextCache !== prevState.cache) { - // This cache refreshed. Propagate a context change. - propagateContextChange(workInProgress, CacheContext, renderLanes); - } - } - } + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, renderLanes); + } - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} // This should only be called if the name changes + scheduleContextWorkOnParentPath( + consumer.return, + renderLanes, + workInProgress + ); -function updateTracingMarkerComponent(current, workInProgress, renderLanes) { - if (!enableTransitionTracing) { - return null; - } // TODO: (luna) Only update the tracing marker if it's newly rendered or it's name changed. - // A tracing marker is only associated with the transitions that rendered - // or updated it, so we can create a new set of transitions each time + if (!forcePropagateEntireTree) { + // During lazy propagation, when we find a match, we can defer + // propagating changes to the children, because we're going to + // visit them during render. We should continue propagating the + // siblings, though + nextFiber = null; + } // Since we already found a match, we can stop traversing the + // dependency list. - if (current === null) { - var currentTransitions = getPendingTransitions(); + break findChangedDep; + } + } - if (currentTransitions !== null) { - var markerInstance = { - tag: TransitionTracingMarker, - transitions: new Set(currentTransitions), - pendingBoundaries: null, - name: workInProgress.pendingProps.name, - aborts: null - }; - workInProgress.stateNode = markerInstance; // We call the marker complete callback when all child suspense boundaries resolve. - // We do this in the commit phase on Offscreen. If the marker has no child suspense - // boundaries, we need to schedule a passive effect to make sure we call the marker - // complete callback. + dep = dependency.next; + } + } else if (fiber.tag === DehydratedFragment) { + // If a dehydrated suspense boundary 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. + var parentSuspense = fiber.return; - workInProgress.flags |= Passive$1; - } - } else { - { - if (current.memoizedProps.name !== workInProgress.pendingProps.name) { - error( - "Changing the name of a tracing marker after mount is not supported. " + - "To remount the tracing marker, pass it a new key." + if (parentSuspense === null) { + throw new Error( + "We just came from a parent so we must have had a parent. This is a bug in React." ); } - } - } - var instance = workInProgress.stateNode; + parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); + var _alternate2 = parentSuspense.alternate; - if (instance !== null) { - pushMarkerInstance(workInProgress, instance); - } + if (_alternate2 !== null) { + _alternate2.lanes = mergeLanes(_alternate2.lanes, renderLanes); + } // 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 childLanes on + // this fiber to indicate that a context has changed. - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + scheduleContextWorkOnParentPath( + parentSuspense, + renderLanes, + workInProgress + ); + nextFiber = null; + } else { + // Traverse down. + nextFiber = fiber.child; + } -function updateFragment(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.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; -function updateMode(current, workInProgress, renderLanes) { - var nextChildren = workInProgress.pendingProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } -function updateProfiler(current, workInProgress, renderLanes) { - { - workInProgress.flags |= Update; + var sibling = nextFiber.sibling; - { - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - var stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + 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; + } } - } - var nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + fiber = nextFiber; + } } -function markRef$1(current, workInProgress) { - var ref = workInProgress.ref; +function lazilyPropagateParentContextChanges( + current, + workInProgress, + renderLanes +) { + var forcePropagateEntireTree = false; + propagateParentContextChanges( + current, + workInProgress, + renderLanes, + forcePropagateEntireTree + ); +} // Used for propagating a deferred tree (Suspense, Offscreen). We must propagate +// to the entire subtree, because we won't revisit it until after the current +// render has completed, at which point we'll have lost track of which providers +// have changed. - if ( - (current === null && ref !== null) || - (current !== null && current.ref !== ref) - ) { - // Schedule a Ref effect - workInProgress.flags |= Ref; - workInProgress.flags |= RefStatic; - } +function propagateParentContextChangesToDeferredTree( + current, + workInProgress, + renderLanes +) { + var forcePropagateEntireTree = true; + propagateParentContextChanges( + current, + workInProgress, + renderLanes, + forcePropagateEntireTree + ); } -function updateFunctionComponent( +function propagateParentContextChanges( current, workInProgress, - Component, - nextProps, - renderLanes + renderLanes, + forcePropagateEntireTree ) { - { - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var innerPropTypes = Component.propTypes; + if (!enableLazyContextPropagation) { + return; + } // Collect all the parent providers that changed. Since this is usually small + // number, we use an Array instead of Set. - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(Component) - ); + var contexts = null; + var parent = workInProgress; + var isInsidePropagationBailout = false; + + while (parent !== null) { + if (!isInsidePropagationBailout) { + if ((parent.flags & NeedsPropagation) !== NoFlags$1) { + isInsidePropagationBailout = true; + } else if ((parent.flags & DidPropagateContext) !== NoFlags$1) { + break; } } - } - var context; + if (parent.tag === ContextProvider) { + var currentParent = parent.alternate; - { - var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); - context = getMaskedContext(workInProgress, unmaskedContext); - } + if (currentParent === null) { + throw new Error("Should have a current fiber. This is a bug in React."); + } - var nextChildren; - var hasId; - prepareToReadContext(workInProgress, renderLanes); + var oldProps = currentParent.memoizedProps; - if (enableSchedulingProfiler) { - markComponentRenderStarted(workInProgress); + if (oldProps !== null) { + var providerType = parent.type; + var context = providerType._context; + var newProps = parent.pendingProps; + var newValue = newProps.value; + var oldValue = oldProps.value; + + if (!objectIs(newValue, oldValue)) { + if (contexts !== null) { + contexts.push(context); + } else { + contexts = [context]; + } + } + } + } + + parent = parent.return; } - { - ReactCurrentOwner$2.current = workInProgress; - setIsRendering(true); - nextChildren = renderWithHooks( - current, + if (contexts !== null) { + // If there were any changed providers, search through the children and + // propagate their changes. + propagateContextChanges( workInProgress, - Component, - nextProps, - context, - renderLanes + contexts, + renderLanes, + forcePropagateEntireTree ); - hasId = checkDidRenderIdHook(); - setIsRendering(false); - } + } // This is an optimization so that we only propagate once per subtree. If a + // deeply nested child bails out, and it calls this propagation function, it + // uses this flag to know that the remaining ancestor providers have already + // been propagated. + // + // NOTE: This optimization is only necessary because we sometimes enter the + // begin phase of nodes that don't have any work scheduled on them — + // specifically, the siblings of a node that _does_ have scheduled work. The + // siblings will bail out and call this function again, even though we already + // propagated content changes to it and its subtree. So we use this flag to + // mark that the parent providers already propagated. + // + // Unfortunately, though, we need to ignore this flag when we're inside a + // tree whose context propagation was deferred — that's what the + // `NeedsPropagation` flag is for. + // + // If we could instead bail out before entering the siblings' begin phase, + // then we could remove both `DidPropagateContext` and `NeedsPropagation`. + // Consider this as part of the next refactor to the fiber tree structure. - if (enableSchedulingProfiler) { - markComponentRenderStopped(); - } + workInProgress.flags |= DidPropagateContext; +} - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); - } +function checkIfContextChanged(currentDependencies) { + if (!enableLazyContextPropagation) { + return false; + } // Iterate over the current dependencies to see if something changed. This + // only gets called if props and state has already bailed out, so it's a + // relatively uncommon path, except at the root of a changed subtree. + // Alternatively, we could move these comparisons into `readContext`, but + // that's a much hotter path, so I think this is an appropriate trade off. - if (getIsHydrating() && hasId) { - pushMaterializedTreeId(workInProgress); - } // React DevTools reads this flag. + var dependency = currentDependencies.firstContext; - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + while (dependency !== null) { + var context = dependency.context; + var newValue = context._currentValue; + var oldValue = dependency.memoizedValue; -function replayFunctionComponent( - current, - workInProgress, - nextProps, - Component, - renderLanes -) { - // This function is used to replay a component that previously suspended, - // after its data resolves. It's a simplified version of - // updateFunctionComponent that reuses the hooks from the previous attempt. - var context; + if (!objectIs(newValue, oldValue)) { + return true; + } - { - var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); - context = getMaskedContext(workInProgress, unmaskedContext); + dependency = dependency.next; } - prepareToReadContext(workInProgress, renderLanes); - - if (enableSchedulingProfiler) { - markComponentRenderStarted(workInProgress); - } + return false; +} +function prepareToReadContext(workInProgress, renderLanes) { + currentlyRenderingFiber = workInProgress; + lastContextDependency = null; + lastFullyObservedContext = null; + var dependencies = workInProgress.dependencies; - var nextChildren = replaySuspendedComponentWithHooks( - current, - workInProgress, - Component, - nextProps, - context - ); - var hasId = checkDidRenderIdHook(); + if (dependencies !== null) { + if (enableLazyContextPropagation) { + // Reset the work-in-progress list + dependencies.firstContext = null; + } else { + var firstContext = dependencies.firstContext; - if (enableSchedulingProfiler) { - markComponentRenderStopped(); - } + if (firstContext !== null) { + if (includesSomeLane(dependencies.lanes, renderLanes)) { + // Context list has a pending update. Mark that this fiber performed work. + markWorkInProgressReceivedUpdate(); + } // Reset the work-in-progress list - if (current !== null && !didReceiveUpdate) { - bailoutHooks(current, workInProgress, renderLanes); - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + dependencies.firstContext = null; + } + } } - - if (getIsHydrating() && hasId) { - pushMaterializedTreeId(workInProgress); - } // React DevTools reads this flag. - - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; } - -function updateClassComponent( - current, - workInProgress, - Component, - nextProps, - renderLanes -) { +function readContext(context) { { - // This is used by DevTools to force a boundary to error. - switch (shouldError(workInProgress)) { - case false: { - var _instance = workInProgress.stateNode; - var ctor = workInProgress.type; // TODO This way of resetting the error boundary state is a hack. - // Is there a better way to do this? - - var tempInstance = new ctor( - workInProgress.memoizedProps, - _instance.context - ); - var state = tempInstance.state; + // This warning would fire if you read context inside a Hook like useMemo. + // Unlike the class check below, it's not enforced in production for perf. + if (isDisallowedContextReadInDEV) { + error( + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." + ); + } + } - _instance.updater.enqueueSetState(_instance, state, null); + return readContextForConsumer(currentlyRenderingFiber, context); +} +function readContextDuringReconcilation(consumer, context, renderLanes) { + if (currentlyRenderingFiber === null) { + prepareToReadContext(consumer, renderLanes); + } - break; - } + return readContextForConsumer(consumer, context); +} - case true: { - workInProgress.flags |= DidCapture; - workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes +function readContextForConsumer(consumer, context) { + var value = context._currentValue; - var error$1 = new Error("Simulated error coming from DevTools"); - var lane = pickArbitraryLane(renderLanes); - workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); // Schedule the error boundary to re-render using updated state + if (lastFullyObservedContext === context); + else { + var contextItem = { + context: context, + memoizedValue: value, + next: null + }; - var update = createClassErrorUpdate( - workInProgress, - createCapturedValueAtFiber(error$1, workInProgress), - lane + if (lastContextDependency === null) { + if (consumer === null) { + throw new Error( + "Context can only be read while React is rendering. " + + "In classes, you can read it in the render method or getDerivedStateFromProps. " + + "In function components, you can read it directly in the function body, but not " + + "inside Hooks like useReducer() or useMemo()." ); - enqueueCapturedUpdate(workInProgress, update); - break; - } - } + } // This is the first dependency for this component. Create a new list. - if (workInProgress.type !== workInProgress.elementType) { - // Lazy component props can't be validated in createElement - // because they're only guaranteed to be resolved here. - var innerPropTypes = Component.propTypes; + lastContextDependency = contextItem; + consumer.dependencies = { + lanes: NoLanes, + firstContext: contextItem + }; - if (innerPropTypes) { - checkPropTypes( - innerPropTypes, - nextProps, // Resolved props - "prop", - getComponentNameFromType(Component) - ); + if (enableLazyContextPropagation) { + consumer.flags |= NeedsPropagation; } + } else { + // Append a new context item. + lastContextDependency = lastContextDependency.next = contextItem; } - } // 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; + return value; +} - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; - } +// replace it with a lightweight shim that only has the features we use. - prepareToReadContext(workInProgress, renderLanes); - var instance = workInProgress.stateNode; - var shouldUpdate; +var AbortControllerLocal = + typeof AbortController !== "undefined" + ? AbortController // $FlowFixMe[missing-this-annot] + : function AbortControllerShim() { + var listeners = []; + var signal = (this.signal = { + aborted: false, + addEventListener: function (type, listener) { + listeners.push(listener); + } + }); - if (instance === null) { - resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress); // In the initial pass we might need to construct the instance. + this.abort = function () { + signal.aborted = true; + listeners.forEach(function (listener) { + return listener(); + }); + }; + }; // Intentionally not named imports because Rollup would +// use dynamic dispatch for CommonJS interop named imports. - constructClassInstance(workInProgress, Component, nextProps); - mountClassInstance(workInProgress, Component, nextProps, renderLanes); - shouldUpdate = true; - } else if (current === null) { - // In a resume, we'll already have an instance we can reuse. - shouldUpdate = resumeMountClassInstance( - workInProgress, - Component, - nextProps, - renderLanes - ); - } else { - shouldUpdate = updateClassInstance( - current, - workInProgress, - Component, - nextProps, - renderLanes - ); - } +var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, + NormalPriority = Scheduler.unstable_NormalPriority; +var CacheContext = { + $$typeof: REACT_CONTEXT_TYPE, + // We don't use Consumer/Provider for Cache components. So we'll cheat. + Consumer: null, + Provider: null, + // We'll initialize these at the root. + _currentValue: null, + _currentValue2: null, + _threadCount: 0, + _defaultValue: null, + _globalName: null +}; - var nextUnitOfWork = finishClassComponent( - current, - workInProgress, - Component, - shouldUpdate, - hasContext, - renderLanes - ); +{ + CacheContext._currentRenderer = null; + CacheContext._currentRenderer2 = null; +} // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible +// for retaining the cache once it is in use (retainCache), and releasing the cache +// once it is no longer needed (releaseCache). +function createCache() { + var cache = { + controller: new AbortControllerLocal(), + data: new Map(), + refCount: 0 + }; + return cache; +} +function retainCache(cache) { { - var inst = workInProgress.stateNode; - - if (shouldUpdate && inst.props !== nextProps) { - if (!didWarnAboutReassigningProps) { - error( - "It looks like %s is reassigning its own `this.props` while rendering. " + - "This is not supported and can lead to confusing bugs.", - getComponentNameFromFiber(workInProgress) || "a component" - ); - } - - didWarnAboutReassigningProps = true; + if (cache.controller.signal.aborted) { + warn( + "A cache instance was retained after it was already freed. " + + "This likely indicates a bug in React." + ); } } - return nextUnitOfWork; -} + cache.refCount++; +} // Cleanup a cache instance, potentially freeing it if there are no more references -function finishClassComponent( - current, - workInProgress, - Component, - shouldUpdate, - hasContext, - renderLanes -) { - // Refs should update even if shouldComponentUpdate returns false - markRef$1(current, workInProgress); - var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags$1; +function releaseCache(cache) { + cache.refCount--; - if (!shouldUpdate && !didCaptureError) { - // Context providers should defer to sCU for rendering - if (hasContext) { - invalidateContextProvider(workInProgress, Component, false); + { + if (cache.refCount < 0) { + warn( + "A cache instance was released after it was already freed. " + + "This likely indicates a bug in React." + ); } - - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); } - var instance = workInProgress.stateNode; // Rerender - - ReactCurrentOwner$2.current = workInProgress; - var nextChildren; + if (cache.refCount === 0) { + scheduleCallback$1(NormalPriority, function () { + cache.controller.abort(); + }); + } +} +function pushCacheProvider(workInProgress, cache) { + pushProvider(workInProgress, CacheContext, cache); +} +function popCacheProvider(workInProgress, cache) { + popProvider(CacheContext, workInProgress); +} - if ( - didCaptureError && - typeof Component.getDerivedStateFromError !== "function" - ) { - // If we captured an error, but getDerivedStateFromError 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; +var ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig; +var NoTransition = null; +function requestCurrentTransition() { + return ReactCurrentBatchConfig$2.transition; +} // When retrying a Suspense/Offscreen boundary, we restore the cache that was +// used during the previous render by placing it here, on the stack. - { - stopProfilerTimerIfRunning(); - } - } else { - if (enableSchedulingProfiler) { - markComponentRenderStarted(workInProgress); - } +var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the +// transitions. Therefore, we want to lazily combine transitions. Instead of +// comparing the arrays of transitions when we combine them and storing them +// and filtering out the duplicates, we will instead store the unprocessed transitions +// in an array and actually filter them in the passive phase. - { - setIsRendering(true); - nextChildren = instance.render(); +var transitionStack = createCursor(null); - if (workInProgress.mode & StrictLegacyMode) { - setIsStrictModeForDevtools(true); +function peekCacheFromPool() { + // If we're rendering inside a Suspense boundary that is currently hidden, + // we should use the same cache that we used during the previous render, if + // one exists. - try { - instance.render(); - } finally { - setIsStrictModeForDevtools(false); - } - } + var cacheResumedFromPreviousRender = resumedCache.current; - setIsRendering(false); - } + if (cacheResumedFromPreviousRender !== null) { + return cacheResumedFromPreviousRender; + } // Otherwise, check the root's cache pool. - if (enableSchedulingProfiler) { - markComponentRenderStopped(); - } - } // React DevTools reads this flag. + var root = getWorkInProgressRoot(); + var cacheFromRootCachePool = root.pooledCache; + return cacheFromRootCachePool; +} - workInProgress.flags |= PerformedWork; +function requestCacheFromPool(renderLanes) { + // Similar to previous function, except if there's not already a cache in the + // pool, we allocate a new one. + var cacheFromPool = peekCacheFromPool(); - if (current !== 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, - workInProgress, - nextChildren, - renderLanes - ); - } else { - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - } // Memoize state using the values we just used to render. - // TODO: Restructure so we never read values from the instance. + if (cacheFromPool !== null) { + return cacheFromPool; + } // Create a fresh cache and add it to the root cache pool. A cache can have + // multiple owners: + // - A cache pool that lives on the FiberRoot. This is where all fresh caches + // are originally created (TODO: except during refreshes, until we implement + // this correctly). The root takes ownership immediately when the cache is + // created. Conceptually, root.pooledCache is an Option> (owned), + // and the return value of this function is a &Arc (borrowed). + // - One of several fiber types: host root, cache boundary, suspense + // component. These retain and release in the commit phase. - workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it. + var root = getWorkInProgressRoot(); + var freshCache = createCache(); + root.pooledCache = freshCache; + retainCache(freshCache); - if (hasContext) { - invalidateContextProvider(workInProgress, Component, true); + if (freshCache !== null) { + root.pooledCacheLanes |= renderLanes; } - return workInProgress.child; + return freshCache; } - -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); +function pushRootTransition(workInProgress, root, renderLanes) { + if (enableTransitionTracing) { + var rootTransitions = getWorkInProgressTransitions(); + push(transitionStack, rootTransitions, workInProgress); } - - pushHostContainer(workInProgress, root.containerInfo); } - -function updateHostRoot(current, workInProgress, renderLanes) { - pushHostRootContext(workInProgress); - - if (current === null) { - throw new Error("Should have a current fiber. This is a bug in React."); - } - - var nextProps = workInProgress.pendingProps; - var prevState = workInProgress.memoizedState; - var prevChildren = prevState.element; - cloneUpdateQueue(current, workInProgress); - processUpdateQueue(workInProgress, nextProps, null, renderLanes); - var nextState = workInProgress.memoizedState; - var root = workInProgress.stateNode; - pushRootTransition(workInProgress); - +function popRootTransition(workInProgress, root, renderLanes) { if (enableTransitionTracing) { - pushRootMarkerInstance(workInProgress); + pop(transitionStack, workInProgress); } - +} +function pushTransition( + offscreenWorkInProgress, + prevCachePool, + newTransitions +) { { - var nextCache = nextState.cache; - pushCacheProvider(workInProgress, nextCache); - - if (nextCache !== prevState.cache) { - // The root cache refreshed. - propagateContextChange(workInProgress, CacheContext, renderLanes); + if (prevCachePool === null) { + push(resumedCache, resumedCache.current, offscreenWorkInProgress); + } else { + push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); } - } // Caution: React DevTools currently depends on this property - // being called "element". - - var nextChildren = nextState.element; - - if (prevState.isDehydrated) { - // This is a hydration root whose shell has not yet hydrated. We should - // attempt to hydrate. - // Flip isDehydrated to false to indicate that when this render - // finishes, the root will no longer be dehydrated. - var overrideState = { - element: nextChildren, - isDehydrated: false, - cache: nextState.cache - }; - var updateQueue = workInProgress.updateQueue; // `baseState` can always be the last state because the root doesn't - // have reducer functions so it doesn't need rebasing. - - updateQueue.baseState = overrideState; - workInProgress.memoizedState = overrideState; - - if (workInProgress.flags & ForceClientRender) { - // Something errored during a previous attempt to hydrate the shell, so we - // forced a client render. - var recoverableError = createCapturedValueAtFiber( - new Error( - "There was an error while hydrating. Because the error happened outside " + - "of a Suspense boundary, the entire root will switch to " + - "client rendering." - ), - workInProgress - ); - return mountHostRootWithoutHydrating( - current, - workInProgress, - nextChildren, - renderLanes, - recoverableError - ); - } else if (nextChildren !== prevChildren) { - var _recoverableError = createCapturedValueAtFiber( - new Error( - "This root received an early update, before anything was able " + - "hydrate. Switched the entire root to client rendering." - ), - workInProgress - ); + } - return mountHostRootWithoutHydrating( - current, - workInProgress, - nextChildren, - renderLanes, - _recoverableError - ); + if (enableTransitionTracing) { + if (transitionStack.current === null) { + push(transitionStack, newTransitions, offscreenWorkInProgress); + } else if (newTransitions === null) { + push(transitionStack, transitionStack.current, offscreenWorkInProgress); } else { - // The outermost shell has not hydrated yet. Start hydrating. - enterHydrationState(workInProgress); - - { - var mutableSourceEagerHydrationData = - root.mutableSourceEagerHydrationData; - - if (mutableSourceEagerHydrationData != null) { - for (var i = 0; i < mutableSourceEagerHydrationData.length; i += 2) { - var mutableSource = mutableSourceEagerHydrationData[i]; - var version = mutableSourceEagerHydrationData[i + 1]; - setWorkInProgressVersion(mutableSource, version); - } - } - } - - var child = mountChildFibers( - workInProgress, - null, - nextChildren, - renderLanes + push( + transitionStack, + transitionStack.current.concat(newTransitions), + offscreenWorkInProgress ); - workInProgress.child = child; - var node = child; - - while (node) { - // Mark each child as hydrating. This is a fast path to know whether this - // tree is part of a hydrating tree. This is used to determine if a child - // node has fully mounted yet, and for scheduling event replaying. - // Conceptually this is similar to Placement in that a new subtree is - // inserted into the React tree here. It just happens to not need DOM - // mutations because it already exists. - node.flags = (node.flags & ~Placement) | Hydrating; - node = node.sibling; - } } - } else { - // Root is not dehydrated. Either this is a client-only root, or it - // already hydrated. - resetHydrationState(); - - if (nextChildren === prevChildren) { - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + } +} +function popTransition(workInProgress, current) { + if (current !== null) { + if (enableTransitionTracing) { + pop(transitionStack, workInProgress); } - reconcileChildren(current, workInProgress, nextChildren, renderLanes); + { + pop(resumedCache, workInProgress); + } } - - return workInProgress.child; } +function getPendingTransitions() { + if (!enableTransitionTracing) { + return null; + } -function mountHostRootWithoutHydrating( - current, - workInProgress, - nextChildren, - renderLanes, - recoverableError -) { - // Revert to client rendering. - resetHydrationState(); - queueHydrationError(recoverableError); - workInProgress.flags |= ForceClientRender; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + return transitionStack.current; } +function getSuspendedCache() { + // cache that would have been used to render fresh data during this render, + // if there was any, so that we can resume rendering with the same cache when + // we receive more data. -function updateHostComponent$1(current, workInProgress, renderLanes) { - pushHostContext(workInProgress); + var cacheFromPool = peekCacheFromPool(); - if (current === null) { - tryToClaimNextHydratableInstance(workInProgress); + if (cacheFromPool === null) { + return null; } - var type = workInProgress.type; - var nextProps = workInProgress.pendingProps; - var prevProps = current !== null ? current.memoizedProps : null; - var nextChildren = nextProps.children; - var isDirectTextChild = shouldSetTextContent(type, nextProps); + return { + // We must also save the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue, + pool: cacheFromPool + }; +} +function getOffscreenDeferredCache() { + var cacheFromPool = peekCacheFromPool(); - 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 has 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.flags |= ContentReset; + if (cacheFromPool === null) { + return null; } - markRef$1(current, workInProgress); - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; + return { + // We must also store the parent, so that when we resume we can detect + // a refresh. + parent: CacheContext._currentValue, + pool: cacheFromPool + }; } -function updateHostHoistable(current, workInProgress, renderLanes) { - markRef$1(current, workInProgress); - var currentProps = current === null ? null : current.memoizedProps; - var resource = (workInProgress.memoizedState = getResource( - workInProgress.type, - currentProps, - workInProgress.pendingProps - )); - - if (current === null) { - if (!getIsHydrating() && resource === null) { - // This is not a Resource Hoistable and we aren't hydrating so we construct the instance. - workInProgress.stateNode = createHoistableInstance( - workInProgress.type, - workInProgress.pendingProps, - getRootHostContainer(), - workInProgress - ); - } - } // Resources never have reconciler managed children. It is possible for - // the host implementation of getResource to consider children in the - // resource construction but they will otherwise be discarded. In practice - // this precludes all but the simplest children and Host specific warnings - // should be implemented to warn when children are passsed when otherwise not - // expected - - return null; +function getSuspenseFallbackChild(fiber) { + return fiber.child.sibling.child; } -function updateHostSingleton(current, workInProgress, renderLanes) { - pushHostContext(workInProgress); - - if (current === null) { - claimHydratableSingleton(workInProgress); - } +var emptyObject = {}; - var nextChildren = workInProgress.pendingProps.children; +function collectScopedNodes(node, fn, scopedNodes) { + { + if (node.tag === HostComponent) { + var type = node.type, + memoizedProps = node.memoizedProps, + stateNode = node.stateNode; + var instance = getPublicInstance(stateNode); - if (current === null && !getIsHydrating()) { - // Similar to Portals we append Singleton children in the commit phase. So we - // Track insertions even on mount. - // TODO: Consider unifying this with how the root works. - workInProgress.child = reconcileChildFibers( - workInProgress, - null, - nextChildren, - renderLanes - ); - } else { - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - } + if ( + instance !== null && + fn(type, memoizedProps || emptyObject, instance) === true + ) { + scopedNodes.push(instance); + } + } - markRef$1(current, workInProgress); - return workInProgress.child; -} + var child = node.child; -function updateHostText$1(current, workInProgress) { - if (current === null) { - tryToClaimNextHydratableTextInstance(workInProgress); - } // Nothing to do here. This is terminal. We'll do the completion step - // immediately after. + if (isFiberSuspenseAndTimedOut(node)) { + child = getSuspenseFallbackChild(node); + } - return null; + if (child !== null) { + collectScopedNodesFromChildren(child, fn, scopedNodes); + } + } } -function mountLazyComponent( - _current, - workInProgress, - elementType, - renderLanes -) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); - var props = workInProgress.pendingProps; - var lazyComponent = elementType; - var payload = lazyComponent._payload; - var init = lazyComponent._init; - var Component = init(payload); // Store the unwrapped component in the type. - - workInProgress.type = Component; - var resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component)); - var resolvedProps = resolveDefaultProps(Component, props); - var child; +function collectFirstScopedNode(node, fn) { + { + if (node.tag === HostComponent) { + var type = node.type, + memoizedProps = node.memoizedProps, + stateNode = node.stateNode; + var instance = getPublicInstance(stateNode); - switch (resolvedTag) { - case FunctionComponent: { - { - validateFunctionComponentInDev(workInProgress, Component); - workInProgress.type = Component = - resolveFunctionForHotReloading(Component); + if (instance !== null && fn(type, memoizedProps, instance) === true) { + return instance; } - - child = updateFunctionComponent( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - return child; } - case ClassComponent: { - { - workInProgress.type = Component = - resolveClassForHotReloading(Component); - } + var child = node.child; - child = updateClassComponent( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - return child; + if (isFiberSuspenseAndTimedOut(node)) { + child = getSuspenseFallbackChild(node); } - case ForwardRef: { - { - workInProgress.type = Component = - resolveForwardRefForHotReloading(Component); - } - - child = updateForwardRef( - null, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - return child; + if (child !== null) { + return collectFirstScopedNodeFromChildren(child, fn); } + } - case MemoComponent: { - { - if (workInProgress.type !== workInProgress.elementType) { - var outerPropTypes = Component.propTypes; + return null; +} - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - resolvedProps, // Resolved for outer only - "prop", - getComponentNameFromType(Component) - ); - } - } - } +function collectScopedNodesFromChildren(startingChild, fn, scopedNodes) { + var child = startingChild; - child = updateMemoComponent( - null, - workInProgress, - Component, - resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too - renderLanes - ); - return child; + while (child !== null) { + collectScopedNodes(child, fn, scopedNodes); + child = child.sibling; + } +} + +function collectFirstScopedNodeFromChildren(startingChild, fn) { + var child = startingChild; + + while (child !== null) { + var scopedNode = collectFirstScopedNode(child, fn); + + if (scopedNode !== null) { + return scopedNode; } + + child = child.sibling; } - var hint = ""; + return null; +} - { - if ( - Component !== null && - typeof Component === "object" && - Component.$$typeof === REACT_LAZY_TYPE - ) { - hint = " Did you wrap a component in React.lazy() more than once?"; +function collectNearestContextValues(node, context, childContextValues) { + if (node.tag === ContextProvider && node.type._context === context) { + var contextValue = node.memoizedProps.value; + childContextValues.push(contextValue); + } else { + var child = node.child; + + if (isFiberSuspenseAndTimedOut(node)) { + child = getSuspenseFallbackChild(node); } - } // This message intentionally doesn't mention ForwardRef or MemoComponent - // because the fact that it's a separate type of work is an - // implementation detail. - throw new Error( - "Element type is invalid. Received a promise that resolves to: " + - Component + - ". " + - ("Lazy element type must resolve to a class or function." + hint) - ); + if (child !== null) { + collectNearestChildContextValues(child, context, childContextValues); + } + } } -function mountIncompleteClassComponent( - _current, - workInProgress, - Component, - nextProps, - renderLanes +function collectNearestChildContextValues( + startingChild, + context, + childContextValues ) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again. + var child = startingChild; - 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. + while (child !== null) { + collectNearestContextValues(child, context, childContextValues); + child = child.sibling; + } +} - var hasContext; +function DO_NOT_USE_queryAllNodes(fn) { + var currentFiber = getInstanceFromScope(this); - if (isContextProvider(Component)) { - hasContext = true; - pushContextProvider(workInProgress); - } else { - hasContext = false; + if (currentFiber === null) { + return null; } - prepareToReadContext(workInProgress, renderLanes); - constructClassInstance(workInProgress, Component, nextProps); - mountClassInstance(workInProgress, Component, nextProps, renderLanes); - return finishClassComponent( - null, - workInProgress, - Component, - true, - hasContext, - renderLanes - ); + var child = currentFiber.child; + var scopedNodes = []; + + if (child !== null) { + collectScopedNodesFromChildren(child, fn, scopedNodes); + } + + return scopedNodes.length === 0 ? null : scopedNodes; } -function mountIndeterminateComponent( - _current, - workInProgress, - Component, - renderLanes -) { - resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); - var props = workInProgress.pendingProps; - var context; +function DO_NOT_USE_queryFirstNode(fn) { + var currentFiber = getInstanceFromScope(this); - { - var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); - context = getMaskedContext(workInProgress, unmaskedContext); + if (currentFiber === null) { + return null; } - prepareToReadContext(workInProgress, renderLanes); - var value; - var hasId; + var child = currentFiber.child; - if (enableSchedulingProfiler) { - markComponentRenderStarted(workInProgress); + if (child !== null) { + return collectFirstScopedNodeFromChildren(child, fn); } - { - if ( - Component.prototype && - typeof Component.prototype.render === "function" - ) { - var componentName = getComponentNameFromType(Component) || "Unknown"; + return null; +} - if (!didWarnAboutBadClass[componentName]) { - error( - "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + - "This is likely to cause errors. Change %s to extend React.Component instead.", - componentName, - componentName - ); +function containsNode(node) { + var fiber = getInstanceFromNode$1(node); - didWarnAboutBadClass[componentName] = true; - } + while (fiber !== null) { + if (fiber.tag === ScopeComponent && fiber.stateNode === this) { + return true; } - if (workInProgress.mode & StrictLegacyMode) { - ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null); - } + fiber = fiber.return; + } - setIsRendering(true); - ReactCurrentOwner$2.current = workInProgress; - value = renderWithHooks( - null, - workInProgress, - Component, - props, - context, - renderLanes - ); - hasId = checkDidRenderIdHook(); - setIsRendering(false); + return false; +} + +function getChildContextValues(context) { + var currentFiber = getInstanceFromScope(this); + + if (currentFiber === null) { + return []; } - if (enableSchedulingProfiler) { - markComponentRenderStopped(); - } // React DevTools reads this flag. + var child = currentFiber.child; + var childContextValues = []; - workInProgress.flags |= PerformedWork; + if (child !== null) { + collectNearestChildContextValues(child, context, childContextValues); + } - { - // Support for module components is deprecated and is removed behind a flag. - // Whether or not it would crash later, we want to show a good message in DEV first. - if ( - typeof value === "object" && - value !== null && - typeof value.render === "function" && - value.$$typeof === undefined - ) { - var _componentName = getComponentNameFromType(Component) || "Unknown"; + return childContextValues; +} - if (!didWarnAboutModulePatternComponent[_componentName]) { - error( - "The <%s /> component appears to be a function component that returns a class instance. " + - "Change %s to a class that extends React.Component instead. " + - "If you can't use a class try assigning the prototype on the function as a workaround. " + - "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + - "cannot be called with `new` by React.", - _componentName, - _componentName, - _componentName - ); +function createScopeInstance() { + return { + DO_NOT_USE_queryAllNodes: DO_NOT_USE_queryAllNodes, + DO_NOT_USE_queryFirstNode: DO_NOT_USE_queryFirstNode, + containsNode: containsNode, + getChildContextValues: getChildContextValues + }; +} - didWarnAboutModulePatternComponent[_componentName] = true; +function markUpdate(workInProgress) { + // Tag the fiber with an update effect. This turns a Placement into + // a PlacementAndUpdate. + workInProgress.flags |= Update; +} + +function markRef(workInProgress) { + workInProgress.flags |= Ref | RefStatic; +} + +function appendAllChildren( + 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 || node.tag === HostSingleton); + else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } + + if (node === workInProgress) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow + + while (node.sibling === null) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + if (node.return === null || node.return === workInProgress) { + return; + } + + node = node.return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow + + node.sibling.return = node.return; + node = node.sibling; } } +} // An unfortunate fork of appendAllChildren because we have two different parent types. +function updateHostComponent(current, workInProgress, type, newProps) { { - // Proceed under the assumption that this is a function component - workInProgress.tag = FunctionComponent; + // 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 (getIsHydrating() && hasId) { - pushMaterializedTreeId(workInProgress); - } + 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. - reconcileChildren(null, workInProgress, value, renderLanes); + 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`. - { - validateFunctionComponentInDev(workInProgress, Component); - } + var updatePayload = prepareUpdate( + instance, + type, + oldProps, + newProps, + currentHostContext + ); // TODO: Type this specific to this type of component. - return workInProgress.child; + 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); + } } } -function validateFunctionComponentInDev(workInProgress, Component) { +function updateHostText(current, workInProgress, oldText, newText) { { - if (Component) { - if (Component.childContextTypes) { - error( - "%s(...): childContextTypes cannot be defined on a function component.", - Component.displayName || Component.name || "Component" - ); - } + // If the text differs, mark it as an update. All the work in done in commitWork. + if (oldText !== newText) { + markUpdate(workInProgress); } + } +} - if (workInProgress.ref !== null) { - var info = ""; - var ownerName = getCurrentFiberOwnerNameInDevOrNull(); - - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } +function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { + if (getIsHydrating()) { + // If we're hydrating, we should consume as many items as we can + // so we don't leave any behind. + return; + } - var warningKey = ownerName || ""; - var debugSource = workInProgress._debugSource; + switch (renderState.tailMode) { + case "hidden": { + // Any insertions at the end of the tail list after this point + // should be invisible. If there are already mounted boundaries + // anything before them are not considered for collapsing. + // Therefore we need to go through the whole tail to find if + // there are any. + var tailNode = renderState.tail; + var lastTailNode = null; - if (debugSource) { - warningKey = debugSource.fileName + ":" + debugSource.lineNumber; - } + while (tailNode !== null) { + if (tailNode.alternate !== null) { + lastTailNode = tailNode; + } - if (!didWarnAboutFunctionRefs[warningKey]) { - didWarnAboutFunctionRefs[warningKey] = true; + tailNode = tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. - error( - "Function components cannot be given refs. " + - "Attempts to access this ref will fail. " + - "Did you mean to use React.forwardRef()?%s", - info - ); + if (lastTailNode === null) { + // All remaining items in the tail are insertions. + renderState.tail = null; + } else { + // Detach the insertion after the last node that was already + // inserted. + lastTailNode.sibling = null; } + + break; } - if (Component.defaultProps !== undefined) { - var componentName = getComponentNameFromType(Component) || "Unknown"; + case "collapsed": { + // Any insertions at the end of the tail list after this point + // should be invisible. If there are already mounted boundaries + // anything before them are not considered for collapsing. + // Therefore we need to go through the whole tail to find if + // there are any. + var _tailNode = renderState.tail; + var _lastTailNode = null; - if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) { - error( - "%s: Support for defaultProps will be removed from function components " + - "in a future major release. Use JavaScript default parameters instead.", - componentName - ); + while (_tailNode !== null) { + if (_tailNode.alternate !== null) { + _lastTailNode = _tailNode; + } - didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true; + _tailNode = _tailNode.sibling; + } // Next we're simply going to delete all insertions after the + // last rendered item. + + if (_lastTailNode === null) { + // All remaining items in the tail are insertions. + if (!hasRenderedATailFallback && renderState.tail !== null) { + // We suspended during the head. We want to show at least one + // row at the tail. So we'll keep on and cut off the rest. + renderState.tail.sibling = null; + } else { + renderState.tail = null; + } + } else { + // Detach the insertion after the last node that was already + // inserted. + _lastTailNode.sibling = null; } + + break; } + } +} - if (typeof Component.getDerivedStateFromProps === "function") { - var _componentName3 = getComponentNameFromType(Component) || "Unknown"; +function bubbleProperties(completedWork) { + var didBailout = + completedWork.alternate !== null && + completedWork.alternate.child === completedWork.child; + var newChildLanes = NoLanes; + var subtreeFlags = NoFlags$1; - if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) { - error( - "%s: Function components do not support getDerivedStateFromProps.", - _componentName3 + if (!didBailout) { + // Bubble up the earliest expiration time. + if ((completedWork.mode & ProfileMode) !== NoMode) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var actualDuration = completedWork.actualDuration; + var treeBaseDuration = completedWork.selfBaseDuration; + var child = completedWork.child; + + while (child !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(child.lanes, child.childLanes) ); + subtreeFlags |= child.subtreeFlags; + subtreeFlags |= child.flags; // 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. + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true; + actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + + treeBaseDuration += child.treeBaseDuration; + child = child.sibling; } - } - if ( - typeof Component.contextType === "object" && - Component.contextType !== null - ) { - var _componentName4 = getComponentNameFromType(Component) || "Unknown"; + completedWork.actualDuration = actualDuration; + completedWork.treeBaseDuration = treeBaseDuration; + } else { + var _child = completedWork.child; - if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) { - error( - "%s: Function components do not support contextType.", - _componentName4 + while (_child !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(_child.lanes, _child.childLanes) ); + subtreeFlags |= _child.subtreeFlags; + subtreeFlags |= _child.flags; // Update the return pointer so the tree is consistent. This is a code + // smell because it assumes the commit phase is never concurrent with + // the render phase. Will address during refactor to alternate model. - didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true; + _child.return = completedWork; + _child = _child.sibling; } } - } -} -var SUSPENDED_MARKER = { - dehydrated: null, - treeContext: null, - retryLane: NoLane -}; - -function mountSuspenseOffscreenState(renderLanes) { - return { - baseLanes: renderLanes, - cachePool: getSuspendedCache() - }; -} - -function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) { - var cachePool = null; + completedWork.subtreeFlags |= subtreeFlags; + } else { + // Bubble up the earliest expiration time. + if ((completedWork.mode & ProfileMode) !== NoMode) { + // In profiling mode, resetChildExpirationTime is also used to reset + // profiler durations. + var _treeBaseDuration = completedWork.selfBaseDuration; + var _child2 = completedWork.child; - { - var prevCachePool = prevOffscreenState.cachePool; + while (_child2 !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(_child2.lanes, _child2.childLanes) + ); // "Static" flags share the lifetime of the fiber/hook they belong to, + // so we should bubble those up even during a bailout. All the other + // flags have a lifetime only of a single render + commit, so we should + // ignore them. - if (prevCachePool !== null) { - var parentCache = CacheContext._currentValue; + subtreeFlags |= _child2.subtreeFlags & StaticMask; + subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - if (prevCachePool.parent !== parentCache) { - // Detected a refresh in the parent. This overrides any previously - // suspended cache. - cachePool = { - parent: parentCache, - pool: parentCache - }; - } else { - // We can reuse the cache from last time. The only thing that would have - // overridden it is a parent refresh, which we checked for above. - cachePool = prevCachePool; + _treeBaseDuration += _child2.treeBaseDuration; + _child2 = _child2.sibling; } + + completedWork.treeBaseDuration = _treeBaseDuration; } else { - // If there's no previous cache pool, grab the current one. - cachePool = getSuspendedCache(); - } - } + var _child3 = completedWork.child; - return { - baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes), - cachePool: cachePool - }; -} // TODO: Probably should inline this back + while (_child3 !== null) { + newChildLanes = mergeLanes( + newChildLanes, + mergeLanes(_child3.lanes, _child3.childLanes) + ); // "Static" flags share the lifetime of the fiber/hook they belong to, + // so we should bubble those up even during a bailout. All the other + // flags have a lifetime only of a single render + commit, so we should + // ignore them. -function shouldRemainOnFallback(current, workInProgress, renderLanes) { - // If we're already showing a fallback, there are cases where we need to - // remain on that fallback regardless of whether the content has resolved. - // For example, SuspenseList coordinates when nested content appears. - if (current !== null) { - var suspenseState = current.memoizedState; + subtreeFlags |= _child3.subtreeFlags & StaticMask; + subtreeFlags |= _child3.flags & StaticMask; // Update the return pointer so the tree is consistent. This is a code + // smell because it assumes the commit phase is never concurrent with + // the render phase. Will address during refactor to alternate model. - if (suspenseState === null) { - // Currently showing content. Don't hide it, even if ForceSuspenseFallback - // is true. More precise name might be "ForceRemainSuspenseFallback". - // Note: This is a factoring smell. Can't remain on a fallback if there's - // no fallback to remain on. - return false; + _child3.return = completedWork; + _child3 = _child3.sibling; + } } - } // Not currently showing content. Consult the Suspense context. - var suspenseContext = suspenseStackCursor.current; - return hasSuspenseListContext(suspenseContext, ForceSuspenseFallback); -} + completedWork.subtreeFlags |= subtreeFlags; + } -function getRemainingWorkInPrimaryTree(current, renderLanes) { - // TODO: Should not remove render lanes that were pinged during this render - return removeLanes(current.childLanes, renderLanes); + completedWork.childLanes = newChildLanes; + return didBailout; } -function updateSuspenseComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend. - - { - if (shouldSuspend(workInProgress)) { - workInProgress.flags |= DidCapture; - } +function completeDehydratedSuspenseBoundary( + current, + workInProgress, + nextState +) { + if ( + hasUnhydratedTailNodes() && + (workInProgress.mode & ConcurrentMode) !== NoMode && + (workInProgress.flags & DidCapture) === NoFlags$1 + ) { + warnIfUnhydratedTailNodes(workInProgress); + resetHydrationState(); + workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture; + return false; } - var showFallback = false; - var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags$1; - - if (didSuspend || shouldRemainOnFallback(current)) { - // Something in this boundary's subtree already suspended. Switch to - // rendering the fallback children. - showFallback = true; - workInProgress.flags &= ~DidCapture; - } // OK, the next part is confusing. We're about to reconcile the Suspense - // boundary's children. This involves some custom reconciliation logic. Two - // main reasons this is so complicated. - // - // First, Legacy Mode has different semantics for backwards compatibility. The - // primary tree will commit in an inconsistent state, so when we do the - // second pass to render the fallback, we do some exceedingly, uh, clever - // hacks to make that not totally break. Like transferring effects and - // deletions from hidden tree. In Concurrent Mode, it's much simpler, - // because we bailout on the primary tree completely and leave it in its old - // state, no effects. Same as what we do for Offscreen (except that - // Offscreen doesn't have the first render pass). - // - // Second is hydration. During hydration, the Suspense fiber has a slightly - // different layout, where the child points to a dehydrated fragment, which - // contains the DOM rendered by the server. - // - // Third, even if you set all that aside, Suspense is like error boundaries in - // that we first we try to render one tree, and if that fails, we render again - // and switch to a different tree. Like a try/catch block. So we have to track - // which branch we're currently rendering. Ideally we would model this using - // a stack. + var wasHydrated = popHydrationState(workInProgress); - if (current === null) { - // Initial mount - // Special path for hydration - // If we're currently hydrating, try to hydrate this boundary. - if (getIsHydrating()) { - // We must push the suspense handler context *before* attempting to - // hydrate, to avoid a mismatch in case it errors. - if (showFallback) { - pushPrimaryTreeSuspenseHandler(workInProgress); - } else { - pushFallbackTreeSuspenseHandler(workInProgress); + if (nextState !== null && nextState.dehydrated !== null) { + // We might be inside a hydration state the first time we're picking up this + // Suspense boundary, and also after we've reentered it for further hydration. + if (current === null) { + if (!wasHydrated) { + throw new Error( + "A dehydrated suspense component was completed without a hydrated node. " + + "This is probably a bug in React." + ); } - tryToClaimNextHydratableSuspenseInstance(workInProgress); // This could've been a dehydrated suspense component. + prepareToHydrateHostSuspenseInstance(workInProgress); + bubbleProperties(workInProgress); - var suspenseState = workInProgress.memoizedState; + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var isTimedOutSuspense = nextState !== null; - if (suspenseState !== null) { - var dehydrated = suspenseState.dehydrated; + if (isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var primaryChildFragment = workInProgress.child; - if (dehydrated !== null) { - return mountDehydratedSuspenseComponent(workInProgress, dehydrated); + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= + primaryChildFragment.treeBaseDuration; + } + } } - } // If hydration didn't succeed, fall through to the normal Suspense path. - // To avoid a stack mismatch we need to pop the Suspense handler that we - // pushed above. This will become less awkward when move the hydration - // logic to its own fiber. + } - popSuspenseHandler(workInProgress); - } + return false; + } else { + // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration + // state since we're now exiting out of it. popHydrationState doesn't do that for us. + resetHydrationState(); - var nextPrimaryChildren = nextProps.children; - var nextFallbackChildren = nextProps.fallback; + if ((workInProgress.flags & DidCapture) === NoFlags$1) { + // This boundary did not suspend so it's now hydrated and unsuspended. + workInProgress.memoizedState = null; + } // If nothing suspended, we need to schedule an effect to mark this boundary + // as having hydrated so events know that they're free to be invoked. + // It's also a signal to replay events and the suspense callback. + // If something suspended, schedule an effect to attach retry listeners. + // So we might as well always mark this. - if (showFallback) { - pushFallbackTreeSuspenseHandler(workInProgress); - var fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - var primaryChildFragment = workInProgress.child; - primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - workInProgress.memoizedState = SUSPENDED_MARKER; + workInProgress.flags |= Update; + bubbleProperties(workInProgress); - if (enableTransitionTracing) { - var currentTransitions = getPendingTransitions(); + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + var _isTimedOutSuspense = nextState !== null; - if (currentTransitions !== null) { - var parentMarkerInstances = getMarkerInstances(); - var offscreenQueue = primaryChildFragment.updateQueue; + if (_isTimedOutSuspense) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var _primaryChildFragment = workInProgress.child; - if (offscreenQueue === null) { - var newOffscreenQueue = { - transitions: currentTransitions, - markerInstances: parentMarkerInstances, - wakeables: null - }; - primaryChildFragment.updateQueue = newOffscreenQueue; - } else { - offscreenQueue.transitions = currentTransitions; - offscreenQueue.markerInstances = parentMarkerInstances; + if (_primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= + _primaryChildFragment.treeBaseDuration; + } } } } - return fallbackFragment; - } else if (typeof nextProps.unstable_expectedLoadTime === "number") { - // This is a CPU-bound tree. Skip this tree and show a placeholder to - // unblock the surrounding content. Then immediately retry after the - // initial commit. - pushFallbackTreeSuspenseHandler(workInProgress); - - var _fallbackFragment = mountSuspenseFallbackChildren( - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - - var _primaryChildFragment = workInProgress.child; - _primaryChildFragment.memoizedState = - mountSuspenseOffscreenState(renderLanes); - workInProgress.memoizedState = SUSPENDED_MARKER; // TODO: Transition Tracing is not yet implemented for CPU Suspense. - // Since nothing actually suspended, there will nothing to ping this to - // get it started back up to attempt the next item. While in terms of - // priority this work has the same priority as this current render, it's - // not part of the same transition once the transition has committed. If - // it's sync, we still want to yield so that it can be painted. - // Conceptually, this is really the same as pinging. We can use any - // RetryLane even if it's the one currently rendering since we're leaving - // it behind on this node. - - workInProgress.lanes = SomeRetryLane; - return _fallbackFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren); + return false; } } else { - // This is an update. - // Special path for hydration - var prevState = current.memoizedState; - - if (prevState !== null) { - var _dehydrated = prevState.dehydrated; + // Successfully completed this tree. If this was a forced client render, + // there may have been recoverable errors during first hydration + // attempt. If so, add them to a queue so we can log them in the + // commit phase. + upgradeHydrationErrorsToRecoverable(); // Fall through to normal Suspense path - if (_dehydrated !== null) { - return updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - nextProps, - _dehydrated, - prevState, - renderLanes - ); - } - } + return true; + } +} - if (showFallback) { - pushFallbackTreeSuspenseHandler(workInProgress); - var _nextFallbackChildren = nextProps.fallback; - var _nextPrimaryChildren = nextProps.children; - var fallbackChildFragment = updateSuspenseFallbackChildren( - current, - workInProgress, - _nextPrimaryChildren, - _nextFallbackChildren, - renderLanes - ); - var _primaryChildFragment2 = workInProgress.child; - var prevOffscreenState = current.child.memoizedState; - _primaryChildFragment2.memoizedState = - prevOffscreenState === null - ? mountSuspenseOffscreenState(renderLanes) - : updateSuspenseOffscreenState(prevOffscreenState, renderLanes); +function completeWork(current, workInProgress, renderLanes) { + var newProps = workInProgress.pendingProps; // Note: This intentionally doesn't check if we're hydrating because comparing + // to the current tree provider fiber is just as fast and less error-prone. + // Ideally we would have a special version of the work loop only + // for hydration. - if (enableTransitionTracing) { - var _currentTransitions = getPendingTransitions(); + popTreeContext(workInProgress); - if (_currentTransitions !== null) { - var _parentMarkerInstances = getMarkerInstances(); + switch (workInProgress.tag) { + case IndeterminateComponent: + case LazyComponent: + case SimpleMemoComponent: + case FunctionComponent: + case ForwardRef: + case Fragment: + case Mode: + case Profiler: + case ContextConsumer: + case MemoComponent: + bubbleProperties(workInProgress); + return null; - var _offscreenQueue = _primaryChildFragment2.updateQueue; - var currentOffscreenQueue = current.updateQueue; + case ClassComponent: { + var Component = workInProgress.type; - if (_offscreenQueue === null) { - var _newOffscreenQueue = { - transitions: _currentTransitions, - markerInstances: _parentMarkerInstances, - wakeables: null - }; - _primaryChildFragment2.updateQueue = _newOffscreenQueue; - } else if (_offscreenQueue === currentOffscreenQueue) { - // If the work-in-progress queue is the same object as current, we - // can't modify it without cloning it first. - var _newOffscreenQueue2 = { - transitions: _currentTransitions, - markerInstances: _parentMarkerInstances, - wakeables: - currentOffscreenQueue !== null - ? currentOffscreenQueue.wakeables - : null - }; - _primaryChildFragment2.updateQueue = _newOffscreenQueue2; - } else { - _offscreenQueue.transitions = _currentTransitions; - _offscreenQueue.markerInstances = _parentMarkerInstances; - } - } + if (isContextProvider(Component)) { + popContext(workInProgress); } - _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree( - current, - renderLanes - ); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); - var _nextPrimaryChildren2 = nextProps.children; - - var _primaryChildFragment3 = updateSuspensePrimaryChildren( - current, - workInProgress, - _nextPrimaryChildren2, - renderLanes - ); - - workInProgress.memoizedState = null; - return _primaryChildFragment3; + bubbleProperties(workInProgress); + return null; } - } -} - -function mountSuspensePrimaryChildren( - workInProgress, - primaryChildren, - renderLanes -) { - var mode = workInProgress.mode; - var primaryChildProps = { - mode: "visible", - children: primaryChildren - }; - var primaryChildFragment = mountWorkInProgressOffscreenFiber( - primaryChildProps, - mode - ); - primaryChildFragment.return = workInProgress; - workInProgress.child = primaryChildFragment; - return primaryChildFragment; -} - -function mountSuspenseFallbackChildren( - workInProgress, - primaryChildren, - fallbackChildren, - renderLanes -) { - var mode = workInProgress.mode; - var progressedPrimaryFragment = workInProgress.child; - var primaryChildProps = { - mode: "hidden", - children: primaryChildren - }; - var primaryChildFragment; - var fallbackChildFragment; - - if ( - (mode & ConcurrentMode) === NoMode && - progressedPrimaryFragment !== null - ) { - // In legacy mode, we commit the primary tree as if it successfully - // completed, even though it's in an inconsistent state. - primaryChildFragment = progressedPrimaryFragment; - primaryChildFragment.childLanes = NoLanes; - primaryChildFragment.pendingProps = primaryChildProps; - if (workInProgress.mode & ProfileMode) { - // Reset the durations from the first pass so they aren't included in the - // final amounts. This seems counterintuitive, since we're intentionally - // not measuring part of the render phase, but this makes it match what we - // do in Concurrent Mode. - primaryChildFragment.actualDuration = 0; - primaryChildFragment.actualStartTime = -1; - primaryChildFragment.selfBaseDuration = 0; - primaryChildFragment.treeBaseDuration = 0; - } + case HostRoot: { + var fiberRoot = workInProgress.stateNode; - fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - mode, - renderLanes, - null - ); - } else { - primaryChildFragment = mountWorkInProgressOffscreenFiber( - primaryChildProps, - mode - ); - fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - mode, - renderLanes, - null - ); - } + if (enableTransitionTracing) { + var transitions = getWorkInProgressTransitions(); // We set the Passive flag here because if there are new transitions, + // we will need to schedule callbacks and process the transitions, + // which we do in the passive phase - primaryChildFragment.return = workInProgress; - fallbackChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; - return fallbackChildFragment; -} + if (transitions !== null) { + workInProgress.flags |= Passive$1; + } + } -function mountWorkInProgressOffscreenFiber(offscreenProps, mode, renderLanes) { - // The props argument to `createFiberFromOffscreen` is `any` typed, so we use - // this wrapper function to constrain it. - return createFiberFromOffscreen(offscreenProps, mode, NoLanes, null); -} + { + var previousCache = null; -function updateWorkInProgressOffscreenFiber(current, offscreenProps) { - // The props argument to `createWorkInProgress` is `any` typed, so we use this - // wrapper function to constrain it. - return createWorkInProgress(current, offscreenProps); -} + if (current !== null) { + previousCache = current.memoizedState.cache; + } -function updateSuspensePrimaryChildren( - current, - workInProgress, - primaryChildren, - renderLanes -) { - var currentPrimaryChildFragment = current.child; - var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; - var primaryChildFragment = updateWorkInProgressOffscreenFiber( - currentPrimaryChildFragment, - { - mode: "visible", - children: primaryChildren - } - ); + var cache = workInProgress.memoizedState.cache; - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - primaryChildFragment.lanes = renderLanes; - } + if (cache !== previousCache) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; + } - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = null; + popCacheProvider(workInProgress); + } - if (currentFallbackChildFragment !== null) { - // Delete the fallback child fragment - var deletions = workInProgress.deletions; + if (enableTransitionTracing) { + popRootMarkerInstance(workInProgress); + } - if (deletions === null) { - workInProgress.deletions = [currentFallbackChildFragment]; - workInProgress.flags |= ChildDeletion; - } else { - deletions.push(currentFallbackChildFragment); - } - } + popRootTransition(workInProgress); + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + resetWorkInProgressVersions(); - workInProgress.child = primaryChildFragment; - return primaryChildFragment; -} + if (fiberRoot.pendingContext) { + fiberRoot.context = fiberRoot.pendingContext; + fiberRoot.pendingContext = null; + } -function updateSuspenseFallbackChildren( - current, - workInProgress, - primaryChildren, - fallbackChildren, - renderLanes -) { - var mode = workInProgress.mode; - var currentPrimaryChildFragment = current.child; - var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; - var primaryChildProps = { - mode: "hidden", - children: primaryChildren - }; - var primaryChildFragment; + if (current === null || current.child === null) { + // If we hydrated, pop so that we can delete any remaining children + // that weren't hydrated. + var wasHydrated = popHydrationState(workInProgress); - if ( - // In legacy mode, we commit the primary tree as if it successfully - // completed, even though it's in an inconsistent state. - (mode & ConcurrentMode) === NoMode && // Make sure we're on the second pass, i.e. the primary child fragment was - // already cloned. In legacy mode, the only case where this isn't true is - // when DevTools forces us to display a fallback; we skip the first render - // pass entirely and go straight to rendering the fallback. (In Concurrent - // Mode, SuspenseList can also trigger this scenario, but this is a legacy- - // only codepath.) - workInProgress.child !== currentPrimaryChildFragment - ) { - var progressedPrimaryFragment = workInProgress.child; - primaryChildFragment = progressedPrimaryFragment; - primaryChildFragment.childLanes = NoLanes; - primaryChildFragment.pendingProps = primaryChildProps; + if (wasHydrated) { + // If we hydrated, then we'll need to schedule an update for + // the commit side-effects on the root. + markUpdate(workInProgress); + } else { + if (current !== null) { + var prevState = current.memoizedState; - if (workInProgress.mode & ProfileMode) { - // Reset the durations from the first pass so they aren't included in the - // final amounts. This seems counterintuitive, since we're intentionally - // not measuring part of the render phase, but this makes it match what we - // do in Concurrent Mode. - primaryChildFragment.actualDuration = 0; - primaryChildFragment.actualStartTime = -1; - primaryChildFragment.selfBaseDuration = - currentPrimaryChildFragment.selfBaseDuration; - primaryChildFragment.treeBaseDuration = - currentPrimaryChildFragment.treeBaseDuration; - } // The fallback fiber was added as a deletion during the first pass. - // However, since we're going to remain on the fallback, we no longer want - // to delete it. + if ( + // Check if this is a client root + !prevState.isDehydrated || // Check if we reverted to client rendering (e.g. due to an error) + (workInProgress.flags & ForceClientRender) !== NoFlags$1 + ) { + // Schedule an effect to clear this container at the start of the + // next commit. This handles the case of React rendering into a + // container with previous children. It's also safe to do for + // updates too, because current.child would only be null if the + // previous render was null (so the container would already + // be empty). + workInProgress.flags |= Snapshot; // If this was a forced client render, there may have been + // recoverable errors during first hydration attempt. If so, add + // them to a queue so we can log them in the commit phase. - workInProgress.deletions = null; - } else { - primaryChildFragment = updateWorkInProgressOffscreenFiber( - currentPrimaryChildFragment, - primaryChildProps - ); // Since we're reusing a current tree, we need to reuse the flags, too. - // (We don't do this in legacy mode, because in legacy mode we don't re-use - // the current tree; see previous branch.) + upgradeHydrationErrorsToRecoverable(); + } + } + } + } + bubbleProperties(workInProgress); - primaryChildFragment.subtreeFlags = - currentPrimaryChildFragment.subtreeFlags & StaticMask; - } + if (enableTransitionTracing) { + if ((workInProgress.subtreeFlags & Visibility) !== NoFlags$1) { + // If any of our suspense children toggle visibility, this means that + // the pending boundaries array needs to be updated, which we only + // do in the passive phase. + workInProgress.flags |= Passive$1; + } + } - var fallbackChildFragment; + return null; + } - if (currentFallbackChildFragment !== null) { - fallbackChildFragment = createWorkInProgress( - currentFallbackChildFragment, - fallbackChildren - ); - } else { - fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - mode, - renderLanes, - null - ); // Needs a placement effect because the parent (the Suspense boundary) already - // mounted but this is a new fiber. + case HostHoistable: { + { + var currentRef = current ? current.ref : null; - fallbackChildFragment.flags |= Placement; - } + if (currentRef !== workInProgress.ref) { + markRef(workInProgress); + } - fallbackChildFragment.return = workInProgress; - primaryChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; - return fallbackChildFragment; -} + if ( + // We are mounting and must Update this Hoistable in this commit + current === null || // We are transitioning to, from, or between Hoistable Resources + // and require an update + current.memoizedState !== workInProgress.memoizedState + ) { + markUpdate(workInProgress); + } else if (workInProgress.memoizedState === null) { + // We may have props to update on the Hoistable instance. We use the + // updateHostComponent path becuase it produces the update queue + // we need for Hoistables + updateHostComponent( + current, + workInProgress, + workInProgress.type, + workInProgress.pendingProps + ); + } -function retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - recoverableError -) { - // Falling back to client rendering. Because this has performance - // implications, it's considered a recoverable error, even though the user - // likely won't observe anything wrong with the UI. - // - // The error is passed in as an argument to enforce that every caller provide - // a custom message, or explicitly opt out (currently the only path that opts - // out is legacy mode; every concurrent path provides an error). - if (recoverableError !== null) { - queueHydrationError(recoverableError); - } // This will add the old fiber to the deletion list + bubbleProperties(workInProgress); + return null; + } + } + // eslint-disable-next-line-no-fallthrough - reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated. + case HostSingleton: { + { + popHostContext(workInProgress); + var rootContainerInstance = getRootHostContainer(); + var type = workInProgress.type; - var nextProps = workInProgress.pendingProps; - var primaryChildren = nextProps.children; - var primaryChildFragment = mountSuspensePrimaryChildren( - workInProgress, - primaryChildren - ); // Needs a placement effect because the parent (the Suspense boundary) already - // mounted but this is a new fiber. + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent(current, workInProgress, type, newProps); - primaryChildFragment.flags |= Placement; - workInProgress.memoizedState = null; - return primaryChildFragment; -} + if (current.ref !== workInProgress.ref) { + markRef(workInProgress); + } + } else { + if (!newProps) { + if (workInProgress.stateNode === null) { + throw new Error( + "We must have new props for new mounts. This error is likely " + + "caused by a bug in React. Please file an issue." + ); + } // This can happen when we abort work. -function mountSuspenseFallbackAfterRetryWithoutHydrating( - current, - workInProgress, - primaryChildren, - fallbackChildren, - renderLanes -) { - var fiberMode = workInProgress.mode; - var primaryChildProps = { - mode: "visible", - children: primaryChildren - }; - var primaryChildFragment = mountWorkInProgressOffscreenFiber( - primaryChildProps, - fiberMode - ); - var fallbackChildFragment = createFiberFromFragment( - fallbackChildren, - fiberMode, - renderLanes, - null - ); // Needs a placement effect because the parent (the Suspense - // boundary) already mounted but this is a new fiber. + bubbleProperties(workInProgress); + return null; + } - fallbackChildFragment.flags |= Placement; - primaryChildFragment.return = workInProgress; - fallbackChildFragment.return = workInProgress; - primaryChildFragment.sibling = fallbackChildFragment; - workInProgress.child = primaryChildFragment; + var currentHostContext = getHostContext(); - if ((workInProgress.mode & ConcurrentMode) !== NoMode) { - // We will have dropped the effect list which contains the - // deletion. We need to reconcile to delete the current child. - reconcileChildFibers(workInProgress, current.child, null, renderLanes); - } + var _wasHydrated = popHydrationState(workInProgress); - return fallbackChildFragment; -} + if (_wasHydrated) { + // We ignore the boolean indicating there is an updateQueue because + // it is used only to set text children and HostSingletons do not + // use them. + prepareToHydrateHostInstance(workInProgress, currentHostContext); + } else { + workInProgress.stateNode = resolveSingletonInstance( + type, + newProps, + rootContainerInstance, + currentHostContext, + true + ); + markUpdate(workInProgress); + } -function mountDehydratedSuspenseComponent( - workInProgress, - suspenseInstance, - renderLanes -) { - // 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. - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - { - error( - "Cannot hydrate Suspense in legacy mode. Switch from " + - "ReactDOM.hydrate(element, container) to " + - "ReactDOMClient.hydrateRoot(container, )" + - ".render(element) or remove the Suspense components from " + - "the server rendered components." - ); + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef(workInProgress); + } + } + + bubbleProperties(workInProgress); + return null; + } } + // eslint-disable-next-line-no-fallthrough - workInProgress.lanes = laneToLanes(SyncLane); - } else if (isSuspenseInstanceFallback(suspenseInstance)) { - // This is a client-only boundary. Since we won't get any content from the server - // for this, we need to schedule that at a higher priority based on when it would - // have timed out. In theory we could render it in this pass but it would have the - // wrong priority associated with it and will prevent hydration of parent path. - // Instead, we'll leave work left on it to render it in a separate commit. - // TODO This time should be the time at which the server rendered response that is - // a parent to this boundary was displayed. However, since we currently don't have - // a protocol to transfer that time, we'll just estimate it by using the current - // time. This will mean that Suspense timeouts are slightly shifted to later than - // they should be. - // Schedule a normal pri update to render this content. - workInProgress.lanes = laneToLanes(DefaultHydrationLane); - } else { - // We'll continue hydrating the rest at offscreen priority since we'll already - // be showing the right content coming from the server, it is no rush. - workInProgress.lanes = laneToLanes(OffscreenLane); - } + case HostComponent: { + popHostContext(workInProgress); + var _type = workInProgress.type; - return null; -} + if (current !== null && workInProgress.stateNode != null) { + updateHostComponent(current, workInProgress, _type, newProps); -function updateDehydratedSuspenseComponent( - current, - workInProgress, - didSuspend, - nextProps, - suspenseInstance, - suspenseState, - renderLanes -) { - if (!didSuspend) { - // This is the first render pass. Attempt to hydrate. - pushPrimaryTreeSuspenseHandler(workInProgress); // We should never be hydrating at this point because it is the first pass, - // but after we've already committed once. + if (current.ref !== workInProgress.ref) { + markRef(workInProgress); + } + } else { + if (!newProps) { + if (workInProgress.stateNode === null) { + throw new Error( + "We must have new props for new mounts. This error is likely " + + "caused by a bug in React. Please file an issue." + ); + } // This can happen when we abort work. - warnIfHydrating(); + bubbleProperties(workInProgress); + return null; + } - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - null - ); - } + var _currentHostContext2 = 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 whether we want to add them top->down or + // bottom->up. Top->down is faster in IE11. - if (isSuspenseInstanceFallback(suspenseInstance)) { - // This boundary is in a permanent fallback state. In this case, we'll never - // get an update and we'll never be able to hydrate the final content. Let's just try the - // client side render instead. - var digest, message, stack; + var _wasHydrated2 = popHydrationState(workInProgress); - { - var _getSuspenseInstanceF = - getSuspenseInstanceFallbackErrorDetails(suspenseInstance); + if (_wasHydrated2) { + // TODO: Move this and createInstance step into the beginPhase + // to consolidate. + if ( + prepareToHydrateHostInstance(workInProgress, _currentHostContext2) + ) { + // If changes to the hydrated node need to be applied at the + // commit-phase we mark this as such. + markUpdate(workInProgress); + } + } else { + var _rootContainerInstance = getRootHostContainer(); - digest = _getSuspenseInstanceF.digest; - message = _getSuspenseInstanceF.message; - stack = _getSuspenseInstanceF.stack; - } + var instance = createInstance( + _type, + newProps, + _rootContainerInstance, + _currentHostContext2, + workInProgress + ); + appendAllChildren(instance, workInProgress); + workInProgress.stateNode = instance; // 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. - var error; + if (finalizeInitialChildren(instance, _type, newProps)) { + markUpdate(workInProgress); + } + } - if (message) { - // eslint-disable-next-line react-internal/prod-error-codes - error = new Error(message); - } else { - error = new Error( - "The server could not finish this Suspense boundary, likely " + - "due to an error during server rendering. Switched to " + - "client rendering." - ); + if (workInProgress.ref !== null) { + // If there is a ref on a host node we need to schedule a callback + markRef(workInProgress); + } } - error.digest = digest; - var capturedValue = createCapturedValue(error, digest, stack); - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - capturedValue - ); + bubbleProperties(workInProgress); + return null; } - if ( - enableLazyContextPropagation && // TODO: Factoring is a little weird, since we check this right below, too. - // But don't want to re-arrange the if-else chain until/unless this - // feature lands. - !didReceiveUpdate - ) { - // We need to check if any children have context before we decide to bail - // out, so propagate the changes now. - lazilyPropagateParentContextChanges(current, workInProgress, renderLanes); - } // We use lanes 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. + 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(current, workInProgress, oldText, newText); + } else { + if (typeof newText !== "string") { + if (workInProgress.stateNode === null) { + throw new Error( + "We must have new props for new mounts. This error is likely " + + "caused by a bug in React. Please file an issue." + ); + } // This can happen when we abort work. + } - var hasContextChanged = includesSomeLane(renderLanes, current.childLanes); + var _rootContainerInstance2 = getRootHostContainer(); - if (didReceiveUpdate || hasContextChanged) { - // 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 a higher priority lane. - var root = getWorkInProgressRoot(); + var _currentHostContext3 = getHostContext(); - if (root !== null) { - var attemptHydrationAtLane = getBumpedLaneForHydration( - root, - renderLanes - ); + var _wasHydrated3 = popHydrationState(workInProgress); - if ( - attemptHydrationAtLane !== NoLane && - attemptHydrationAtLane !== suspenseState.retryLane - ) { - // Intentionally mutating since this render will get interrupted. This - // is one of the very rare times where we mutate the current tree - // during the render phase. - suspenseState.retryLane = attemptHydrationAtLane; // TODO: Ideally this would inherit the event time of the current render + if (_wasHydrated3) { + if (prepareToHydrateHostTextInstance(workInProgress)) { + markUpdate(workInProgress); + } + } else { + workInProgress.stateNode = createTextInstance( + newText, + _rootContainerInstance2, + _currentHostContext3, + workInProgress + ); + } + } - var eventTime = NoTimestamp; - enqueueConcurrentRenderForLane(current, attemptHydrationAtLane); - scheduleUpdateOnFiber( - root, - current, - attemptHydrationAtLane, - eventTime - ); // Throw a special object that signals to the work loop that it should - // interrupt the current render. - // - // Because we're inside a React-only execution stack, we don't - // strictly need to throw here — we could instead modify some internal - // work loop state. But using an exception means we don't need to - // check for this case on every iteration of the work loop. So doing - // it this way moves the check out of the fast path. + bubbleProperties(workInProgress); + return null; + } - throw SelectiveHydrationException; - } - } // If we did not selectively hydrate, we'll continue rendering without - // hydrating. Mark this tree as suspended to prevent it from committing - // outside a transition. - // - // This path should only happen if the hydration lane already suspended. - // Currently, it also happens during sync updates because there is no - // hydration lane for sync updates. - // TODO: We should ideally have a sync hydration lane that we can apply to do - // a pass where we hydrate this subtree in place using the previous Context and then - // reapply the update afterwards. + case SuspenseComponent: { + popSuspenseHandler(workInProgress); + var nextState = workInProgress.memoizedState; // Special path for dehydrated boundaries. We may eventually move this + // to its own fiber type so that we can add other kinds of hydration + // boundaries that aren't associated with a Suspense tree. In anticipation + // of such a refactor, all the hydration logic is contained in + // this branch. - renderDidSuspendDelayIfPossible(); - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - null - ); - } else if (isSuspenseInstancePending(suspenseInstance)) { - // This component is still pending more data from the server, so we can't hydrate its - // content. We treat it as if this component suspended itself. It might seem as if - // we could just try to render it client-side instead. However, this will perform a - // lot of unnecessary work and is unlikely to complete since it often will suspend - // on missing data anyway. Additionally, the server might be able to render more - // than we can on the client yet. In that case we'd end up with more fallback states - // on the client than if we just leave it alone. If the server times out or errors - // these should update this boundary to the permanent Fallback state instead. - // Mark it as having captured (i.e. suspended). - workInProgress.flags |= DidCapture; // Leave the child in place. I.e. the dehydrated fragment. + if ( + current === null || + (current.memoizedState !== null && + current.memoizedState.dehydrated !== null) + ) { + var fallthroughToNormalSuspensePath = + completeDehydratedSuspenseBoundary( + current, + workInProgress, + nextState + ); - workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result. + if (!fallthroughToNormalSuspensePath) { + if (workInProgress.flags & ShouldCapture) { + // Special case. There were remaining unhydrated nodes. We treat + // this as a mismatch. Revert to client rendering. + return workInProgress; + } else { + // Did not finish hydrating, either because this is the initial + // render or because something suspended. + return null; + } + } // Continue with the normal Suspense path. + } - var retry = retryDehydratedSuspenseBoundary.bind(null, current); - registerSuspenseInstanceRetry(suspenseInstance, retry); - return null; - } else { - // This is the first attempt. - reenterHydrationStateFromDehydratedSuspenseInstance( - workInProgress, - suspenseInstance, - suspenseState.treeContext - ); - var primaryChildren = nextProps.children; - var primaryChildFragment = mountSuspensePrimaryChildren( - workInProgress, - primaryChildren - ); // Mark the children as hydrating. This is a fast path to know whether this - // tree is part of a hydrating tree. This is used to determine if a child - // node has fully mounted yet, and for scheduling event replaying. - // Conceptually this is similar to Placement in that a new subtree is - // inserted into the React tree here. It just happens to not need DOM - // mutations because it already exists. + if ((workInProgress.flags & DidCapture) !== NoFlags$1) { + // Something suspended. Re-render with the fallback children. + workInProgress.lanes = renderLanes; // Do not reset the effect list. - primaryChildFragment.flags |= Hydrating; - return primaryChildFragment; - } - } else { - // This is the second render pass. We already attempted to hydrated, but - // something either suspended or errored. - if (workInProgress.flags & ForceClientRender) { - // Something errored during hydration. Try again without hydrating. - pushPrimaryTreeSuspenseHandler(workInProgress); - workInProgress.flags &= ~ForceClientRender; + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } // Don't bubble properties in this case. - var _capturedValue = createCapturedValue( - new Error( - "There was an error while hydrating this Suspense boundary. " + - "Switched to client rendering." - ) - ); + return workInProgress; + } - return retrySuspenseComponentWithoutHydrating( - current, - workInProgress, - renderLanes, - _capturedValue - ); - } else if (workInProgress.memoizedState !== null) { - // Something suspended and we should still be in dehydrated mode. - // Leave the existing child in place. - // Push to avoid a mismatch - pushFallbackTreeSuspenseHandler(workInProgress); - workInProgress.child = current.child; // The dehydrated completion pass expects this flag to be there - // but the normal suspense pass doesn't. + var nextDidTimeout = nextState !== null; + var prevDidTimeout = current !== null && current.memoizedState !== null; - workInProgress.flags |= DidCapture; - return null; - } else { - // Suspended but we should no longer be in dehydrated mode. - // Therefore we now have to render the fallback. - pushFallbackTreeSuspenseHandler(workInProgress); - var nextPrimaryChildren = nextProps.children; - var nextFallbackChildren = nextProps.fallback; - var fallbackChildFragment = - mountSuspenseFallbackAfterRetryWithoutHydrating( - current, - workInProgress, - nextPrimaryChildren, - nextFallbackChildren, - renderLanes - ); - var _primaryChildFragment4 = workInProgress.child; - _primaryChildFragment4.memoizedState = - mountSuspenseOffscreenState(renderLanes); - workInProgress.memoizedState = SUSPENDED_MARKER; - return fallbackChildFragment; - } - } -} + if (nextDidTimeout) { + var offscreenFiber = workInProgress.child; + var _previousCache = null; -function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) { - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + if ( + offscreenFiber.alternate !== null && + offscreenFiber.alternate.memoizedState !== null && + offscreenFiber.alternate.memoizedState.cachePool !== null + ) { + _previousCache = + offscreenFiber.alternate.memoizedState.cachePool.pool; + } - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } + var _cache = null; - scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot); -} + if ( + offscreenFiber.memoizedState !== null && + offscreenFiber.memoizedState.cachePool !== null + ) { + _cache = offscreenFiber.memoizedState.cachePool.pool; + } -function propagateSuspenseContextChange( - workInProgress, - firstChild, - renderLanes -) { - // Mark any Suspense boundaries with fallbacks as having work to do. - // If they were previously forced into fallbacks, they may now be able - // to unblock. - var node = firstChild; + if (_cache !== _previousCache) { + // Run passive effects to retain/release the cache. + offscreenFiber.flags |= Passive$1; + } + } // If the suspended state of the boundary changes, we need to schedule + // a passive effect, which is when we process the transitions - while (node !== null) { - if (node.tag === SuspenseComponent) { - var state = node.memoizedState; + if (nextDidTimeout !== prevDidTimeout) { + if (enableTransitionTracing) { + var _offscreenFiber = workInProgress.child; + _offscreenFiber.flags |= Passive$1; + } // If the suspended state of the boundary changes, we need to schedule + // an effect to toggle the subtree's visibility. When we switch from + // fallback -> primary, the inner Offscreen fiber schedules this effect + // as part of its normal complete phase. But when we switch from + // primary -> fallback, the inner Offscreen fiber does not have a complete + // phase. So we need to schedule its effect here. + // + // We also use this flag to connect/disconnect the effects, but the same + // logic applies: when re-connecting, the Offscreen fiber's complete + // phase will handle scheduling the effect. It's only when the fallback + // is active that we have to do anything special. - if (state !== null) { - scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); + if (nextDidTimeout) { + var _offscreenFiber2 = workInProgress.child; + _offscreenFiber2.flags |= Visibility; + } } - } else if (node.tag === SuspenseListComponent) { - // If the tail is hidden there might not be an Suspense boundaries - // to schedule work on. In this case we have to schedule it on the - // list itself. - // We don't have to traverse to the children of the list since - // the list will propagate the change when it rerenders. - scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress); - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + var wakeables = workInProgress.updateQueue; - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; + if (wakeables !== null) { + // Schedule an effect to attach a retry listener to the promise. + // TODO: Move to passive phase + workInProgress.flags |= Update; } - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if ( + workInProgress.updateQueue !== null && + workInProgress.memoizedProps.suspenseCallback != null + ) { + // Always notify the callback + // TODO: Move to passive phase + workInProgress.flags |= Update; + } - node.sibling.return = node.return; - node = node.sibling; - } -} + bubbleProperties(workInProgress); -function findLastContentRow(firstChild) { - // This is going to find the last row among these children that is already - // showing content on the screen, as opposed to being in fallback state or - // new. If a row has multiple Suspense boundaries, any of them being in the - // fallback state, counts as the whole row being in a fallback state. - // Note that the "rows" will be workInProgress, but any nested children - // will still be current since we haven't rendered them yet. The mounted - // order may not be the same as the new order. We use the new order. - var row = firstChild; - var lastContentRow = null; + { + if ((workInProgress.mode & ProfileMode) !== NoMode) { + if (nextDidTimeout) { + // Don't count time spent in a timed out Suspense subtree as part of the base duration. + var primaryChildFragment = workInProgress.child; - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + if (primaryChildFragment !== null) { + // $FlowFixMe Flow doesn't support type casting in combination with the -= operator + workInProgress.treeBaseDuration -= + primaryChildFragment.treeBaseDuration; + } + } + } + } - if (currentRow !== null && findFirstSuspended(currentRow) === null) { - lastContentRow = row; + return null; } - row = row.sibling; - } + case HostPortal: + popHostContainer(workInProgress); - return lastContentRow; -} + if (current === null) { + preparePortalMount(workInProgress.stateNode.containerInfo); + } -function validateRevealOrder(revealOrder) { - { - if ( - revealOrder !== undefined && - revealOrder !== "forwards" && - revealOrder !== "backwards" && - revealOrder !== "together" && - !didWarnAboutRevealOrder[revealOrder] - ) { - didWarnAboutRevealOrder[revealOrder] = true; + bubbleProperties(workInProgress); + return null; - if (typeof revealOrder === "string") { - switch (revealOrder.toLowerCase()) { - case "together": - case "forwards": - case "backwards": { - error( - '"%s" is not a valid value for revealOrder on . ' + - 'Use lowercase "%s" instead.', - revealOrder, - revealOrder.toLowerCase() - ); + case ContextProvider: + // Pop provider fiber + var context = workInProgress.type._context; + popProvider(context, workInProgress); + bubbleProperties(workInProgress); + return null; - 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; - case "forward": - case "backward": { - error( - '"%s" is not a valid value for revealOrder on . ' + - 'React uses the -s suffix in the spelling. Use "%ss" instead.', - revealOrder, - revealOrder.toLowerCase() - ); + if (isContextProvider(_Component)) { + popContext(workInProgress); + } - break; - } + bubbleProperties(workInProgress); + return null; + } - default: - error( - '"%s" is not a supported revealOrder on . ' + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); + case SuspenseListComponent: { + popSuspenseListContext(workInProgress); + var renderState = workInProgress.memoizedState; - break; - } - } else { - error( - "%s is not a supported value for revealOrder on . " + - 'Did you mean "together", "forwards" or "backwards"?', - revealOrder - ); + if (renderState === null) { + // We're running in the default, "independent" mode. + // We don't do anything in this mode. + bubbleProperties(workInProgress); + return null; } - } - } -} -function validateTailOptions(tailMode, revealOrder) { - { - if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) { - if (tailMode !== "collapsed" && tailMode !== "hidden") { - didWarnAboutTailOptions[tailMode] = true; + var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags$1; + var renderedTail = renderState.rendering; - error( - '"%s" is not a supported value for tail on . ' + - 'Did you mean "collapsed" or "hidden"?', - tailMode - ); - } else if (revealOrder !== "forwards" && revealOrder !== "backwards") { - didWarnAboutTailOptions[tailMode] = true; + if (renderedTail === null) { + // We just rendered the head. + if (!didSuspendAlready) { + // This is the first pass. We need to figure out if anything is still + // suspended in the rendered set. + // If new content unsuspended, but there's still some content that + // didn't. Then we need to do a second pass that forces everything + // to keep showing their fallbacks. + // We might be suspended if something in this render pass suspended, or + // something in the previous committed pass suspended. Otherwise, + // there's no chance so we can skip the expensive call to + // findFirstSuspended. + var cannotBeSuspended = + renderHasNotSuspendedYet() && + (current === null || (current.flags & DidCapture) === NoFlags$1); - error( - ' is only valid if revealOrder is ' + - '"forwards" or "backwards". ' + - 'Did you mean to specify revealOrder="forwards"?', - tailMode - ); - } - } - } -} + if (!cannotBeSuspended) { + var row = workInProgress.child; -function validateSuspenseListNestedChild(childSlot, index) { - { - var isAnArray = isArray(childSlot); - var isIterable = - !isAnArray && typeof getIteratorFn(childSlot) === "function"; + while (row !== null) { + var suspended = findFirstSuspended(row); - if (isAnArray || isIterable) { - var type = isAnArray ? "array" : "iterable"; + if (suspended !== null) { + didSuspendAlready = true; + workInProgress.flags |= DidCapture; + cutOffTailIfNeeded(renderState, false); // If this is a newly suspended tree, it might not get committed as + // part of the second pass. In that case nothing will subscribe to + // its thenables. Instead, we'll transfer its thenables to the + // SuspenseList so that it can retry if they resolve. + // There might be multiple of these in the list but since we're + // going to wait for all of them anyway, it doesn't really matter + // which ones gets to ping. In theory we could get clever and keep + // track of how many dependencies remain but it gets tricky because + // in the meantime, we can add/remove/change items and dependencies. + // We might bail out of the loop before finding any but that + // doesn't matter since that means that the other boundaries that + // we did find already has their listeners attached. - error( - "A nested %s was passed to row #%s in . Wrap it in " + - "an additional SuspenseList to configure its revealOrder: " + - " ... " + - "{%s} ... " + - "", - type, - index, - type - ); + var newThenables = suspended.updateQueue; + + if (newThenables !== null) { + workInProgress.updateQueue = newThenables; + workInProgress.flags |= Update; + } // Rerender the whole list, but this time, we'll force fallbacks + // to stay in place. + // Reset the effect flags before doing the second pass since that's now invalid. + // Reset the child fibers to their original state. + + workInProgress.subtreeFlags = NoFlags$1; + resetChildFibers(workInProgress, renderLanes); // Set up the Suspense List Context to force suspense and + // immediately rerender the children. + + pushSuspenseListContext( + workInProgress, + setShallowSuspenseListContext( + suspenseStackCursor.current, + ForceSuspenseFallback + ) + ); // Don't bubble properties in this case. + + return workInProgress.child; + } - return false; - } - } + row = row.sibling; + } + } - return true; -} + if (renderState.tail !== null && now$1() > getRenderTargetTime()) { + // We have already passed our CPU deadline but we still have rows + // left in the tail. We'll just give up further attempts to render + // the main content and only render fallbacks. + workInProgress.flags |= DidCapture; + didSuspendAlready = true; + cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this + // to get it started back up to attempt the next item. While in terms + // of priority this work has the same priority as this current render, + // it's not part of the same transition once the transition has + // committed. If it's sync, we still want to yield so that it can be + // painted. Conceptually, this is really the same as pinging. + // We can use any RetryLane even if it's the one currently rendering + // since we're leaving it behind on this node. -function validateSuspenseListChildren(children, revealOrder) { - { - if ( - (revealOrder === "forwards" || revealOrder === "backwards") && - children !== undefined && - children !== null && - children !== false - ) { - if (isArray(children)) { - for (var i = 0; i < children.length; i++) { - if (!validateSuspenseListNestedChild(children[i], i)) { - return; + workInProgress.lanes = SomeRetryLane; } - } + } else { + cutOffTailIfNeeded(renderState, false); + } // Next we're going to render the tail. } else { - var iteratorFn = getIteratorFn(children); + // Append the rendered row to the child list. + if (!didSuspendAlready) { + var _suspended = findFirstSuspended(renderedTail); - if (typeof iteratorFn === "function") { - var childrenIterator = iteratorFn.call(children); + if (_suspended !== null) { + workInProgress.flags |= DidCapture; + didSuspendAlready = true; // Ensure we transfer the update queue to the parent so that it doesn't + // get lost if this row ends up dropped during a second pass. - if (childrenIterator) { - var step = childrenIterator.next(); - var _i = 0; + var _newThenables = _suspended.updateQueue; - for (; !step.done; step = childrenIterator.next()) { - if (!validateSuspenseListNestedChild(step.value, _i)) { - return; - } + if (_newThenables !== null) { + workInProgress.updateQueue = _newThenables; + workInProgress.flags |= Update; + } - _i++; + cutOffTailIfNeeded(renderState, true); // This might have been modified. + + if ( + renderState.tail === null && + renderState.tailMode === "hidden" && + !renderedTail.alternate && + !getIsHydrating() // We don't cut it if we're hydrating. + ) { + // We're done. + bubbleProperties(workInProgress); + return null; } + } else if ( + // The time it took to render last row is greater than the remaining + // time we have to render. So rendering one more row would likely + // exceed it. + now$1() * 2 - renderState.renderingStartTime > + getRenderTargetTime() && + renderLanes !== OffscreenLane + ) { + // We have now passed our CPU deadline and we'll just give up further + // attempts to render the main content and only render fallbacks. + // The assumption is that this is usually faster. + workInProgress.flags |= DidCapture; + didSuspendAlready = true; + cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this + // to get it started back up to attempt the next item. While in terms + // of priority this work has the same priority as this current render, + // it's not part of the same transition once the transition has + // committed. If it's sync, we still want to yield so that it can be + // painted. Conceptually, this is really the same as pinging. + // We can use any RetryLane even if it's the one currently rendering + // since we're leaving it behind on this node. + + workInProgress.lanes = SomeRetryLane; } + } + + if (renderState.isBackwards) { + // The effect list of the backwards tail will have been added + // to the end. This breaks the guarantee that life-cycles fire in + // sibling order but that isn't a strong guarantee promised by React. + // Especially since these might also just pop in during future commits. + // Append to the beginning of the list. + renderedTail.sibling = workInProgress.child; + workInProgress.child = renderedTail; } else { - error( - 'A single row was passed to a . ' + - "This is not useful since it needs multiple rows. " + - "Did you mean to pass multiple children or an array?", - revealOrder - ); + var previousSibling = renderState.last; + + if (previousSibling !== null) { + previousSibling.sibling = renderedTail; + } else { + workInProgress.child = renderedTail; + } + + renderState.last = renderedTail; } } - } - } -} - -function initSuspenseListRenderState( - workInProgress, - isBackwards, - tail, - lastContentRow, - tailMode -) { - var renderState = workInProgress.memoizedState; - if (renderState === null) { - workInProgress.memoizedState = { - isBackwards: isBackwards, - rendering: null, - renderingStartTime: 0, - last: lastContentRow, - tail: tail, - tailMode: tailMode - }; - } else { - // We can reuse the existing object from previous renders. - renderState.isBackwards = isBackwards; - renderState.rendering = null; - renderState.renderingStartTime = 0; - renderState.last = lastContentRow; - renderState.tail = tail; - renderState.tailMode = tailMode; - } -} // This can end up rendering this component multiple passes. -// The first pass splits the children fibers into two sets. A head and tail. -// We first render the head. If anything is in fallback state, we do another -// pass through beginWork to rerender all children (including the tail) with -// the force suspend context. If the first render didn't have anything in -// in fallback state. Then we render each row in the tail one-by-one. -// That happens in the completeWork phase without going back to beginWork. + if (renderState.tail !== null) { + // We still have tail rows to render. + // Pop a row. + var next = renderState.tail; + renderState.rendering = next; + renderState.tail = next.sibling; + renderState.renderingStartTime = now$1(); + next.sibling = null; // Restore the context. + // TODO: We can probably just avoid popping it instead and only + // setting it the first time we go from not suspended to suspended. -function updateSuspenseListComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; - var revealOrder = nextProps.revealOrder; - var tailMode = nextProps.tail; - var newChildren = nextProps.children; - validateRevealOrder(revealOrder); - validateTailOptions(tailMode, revealOrder); - validateSuspenseListChildren(newChildren, revealOrder); - reconcileChildren(current, workInProgress, newChildren, renderLanes); - var suspenseContext = suspenseStackCursor.current; - var shouldForceFallback = hasSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); + var suspenseContext = suspenseStackCursor.current; - if (shouldForceFallback) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - workInProgress.flags |= DidCapture; - } else { - var didSuspendBefore = - current !== null && (current.flags & DidCapture) !== NoFlags$1; + if (didSuspendAlready) { + suspenseContext = setShallowSuspenseListContext( + suspenseContext, + ForceSuspenseFallback + ); + } else { + suspenseContext = + setDefaultShallowSuspenseListContext(suspenseContext); + } - if (didSuspendBefore) { - // If we previously forced a fallback, we need to schedule work - // on any nested boundaries to let them know to try to render - // again. This is the same as context updating. - propagateSuspenseContextChange( - workInProgress, - workInProgress.child, - renderLanes - ); - } + pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. + // Don't bubble properties in this case. - suspenseContext = setDefaultShallowSuspenseListContext(suspenseContext); - } + return next; + } - pushSuspenseListContext(workInProgress, suspenseContext); + bubbleProperties(workInProgress); + return null; + } - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - // In legacy mode, SuspenseList doesn't work so we just - // use make it a noop by treating it as the default revealOrder. - workInProgress.memoizedState = null; - } else { - switch (revealOrder) { - case "forwards": { - var lastContentRow = findLastContentRow(workInProgress.child); - var tail; + case ScopeComponent: { + { + if (current === null) { + var scopeInstance = createScopeInstance(); + workInProgress.stateNode = scopeInstance; + prepareScopeUpdate(scopeInstance, workInProgress); - if (lastContentRow === null) { - // The whole list is part of the tail. - // TODO: We could fast path by just rendering the tail now. - tail = workInProgress.child; - workInProgress.child = null; + if (workInProgress.ref !== null) { + markRef(workInProgress); + markUpdate(workInProgress); + } } else { - // Disconnect the tail rows after the content row. - // We're going to render them separately later. - tail = lastContentRow.sibling; - lastContentRow.sibling = null; + if (workInProgress.ref !== null) { + markUpdate(workInProgress); + } + + if (current.ref !== workInProgress.ref) { + markRef(workInProgress); + } } - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - tail, - lastContentRow, - tailMode - ); - break; + bubbleProperties(workInProgress); + return null; } + } - case "backwards": { - // We're going to find the first row that has existing content. - // At the same time we're going to reverse the list of everything - // we pass in the meantime. That's going to be our tail in reverse - // order. - var _tail = null; - var row = workInProgress.child; - workInProgress.child = null; + case OffscreenComponent: + case LegacyHiddenComponent: { + popSuspenseHandler(workInProgress); + popHiddenContext(workInProgress); + var _nextState = workInProgress.memoizedState; + var nextIsHidden = _nextState !== null; // Schedule a Visibility effect if the visibility has changed - while (row !== null) { - var currentRow = row.alternate; // New rows can't be content rows. + if (workInProgress.tag === LegacyHiddenComponent); + else { + if (current !== null) { + var _prevState = current.memoizedState; + var prevIsHidden = _prevState !== null; - if (currentRow !== null && findFirstSuspended(currentRow) === null) { - // This is the beginning of the main content. - workInProgress.child = row; - break; + if (prevIsHidden !== nextIsHidden) { + workInProgress.flags |= Visibility; + } + } else { + // On initial mount, we only need a Visibility effect if the tree + // is hidden. + if (nextIsHidden) { + workInProgress.flags |= Visibility; } + } + } - var nextRow = row.sibling; - row.sibling = _tail; - _tail = row; - row = nextRow; - } // TODO: If workInProgress.child is null, we can continue on the tail immediately. + if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) { + bubbleProperties(workInProgress); + } else { + // Don't bubble properties for hidden children unless we're rendering + // at offscreen priority. + if ( + includesSomeLane(renderLanes, OffscreenLane) && // Also don't bubble if the tree suspended + (workInProgress.flags & DidCapture) === NoLanes + ) { + bubbleProperties(workInProgress); // Check if there was an insertion or update in the hidden subtree. + // If so, we need to hide those nodes in the commit phase, so + // schedule a visibility effect. - initSuspenseListRenderState( - workInProgress, - true, // isBackwards - _tail, - null, // last - tailMode - ); - break; + if ( + workInProgress.tag !== LegacyHiddenComponent && + workInProgress.subtreeFlags & (Placement | Update) + ) { + workInProgress.flags |= Visibility; + } + } } - case "together": { - initSuspenseListRenderState( - workInProgress, - false, // isBackwards - null, // tail - null, // last - undefined - ); - break; + if (workInProgress.updateQueue !== null) { + // Schedule an effect to attach Suspense retry listeners + // TODO: Move to passive phase + workInProgress.flags |= Update; } - default: { - // The default reveal order is the same as not having - // a boundary. - workInProgress.memoizedState = null; - } - } - } + { + var _previousCache2 = null; - return workInProgress.child; -} + if ( + current !== null && + current.memoizedState !== null && + current.memoizedState.cachePool !== null + ) { + _previousCache2 = current.memoizedState.cachePool.pool; + } -function updatePortalComponent(current, workInProgress, renderLanes) { - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); - var nextChildren = workInProgress.pendingProps; + var _cache2 = null; - if (current === 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, - renderLanes - ); - } else { - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - } + if ( + workInProgress.memoizedState !== null && + workInProgress.memoizedState.cachePool !== null + ) { + _cache2 = workInProgress.memoizedState.cachePool.pool; + } - return workInProgress.child; -} + if (_cache2 !== _previousCache2) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; + } + } -var hasWarnedAboutUsingNoValuePropOnContextProvider = false; + popTransition(workInProgress, current); + return null; + } -function updateContextProvider(current, workInProgress, renderLanes) { - var providerType = workInProgress.type; - var context = providerType._context; - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; - var newValue = newProps.value; + case CacheComponent: { + { + var _previousCache3 = null; - { - if (!("value" in newProps)) { - if (!hasWarnedAboutUsingNoValuePropOnContextProvider) { - hasWarnedAboutUsingNoValuePropOnContextProvider = true; + if (current !== null) { + _previousCache3 = current.memoizedState.cache; + } - error( - "The `value` prop is required for the ``. Did you misspell it or forget to pass it?" - ); - } - } + var _cache3 = workInProgress.memoizedState.cache; - var providerPropTypes = workInProgress.type.propTypes; + if (_cache3 !== _previousCache3) { + // Run passive effects to retain/release the cache. + workInProgress.flags |= Passive$1; + } - if (providerPropTypes) { - checkPropTypes(providerPropTypes, newProps, "prop", "Context.Provider"); - } - } + popCacheProvider(workInProgress); + bubbleProperties(workInProgress); + } - pushProvider(workInProgress, context, newValue); + return null; + } - if (enableLazyContextPropagation); - else { - if (oldProps !== null) { - var oldValue = oldProps.value; + case TracingMarkerComponent: { + if (enableTransitionTracing) { + var _instance3 = workInProgress.stateNode; - if (objectIs(oldValue, newValue)) { - // No change. Bailout early if children are the same. - if (oldProps.children === newProps.children && !hasContextChanged()) { - return bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + if (_instance3 !== null) { + popMarkerInstance(workInProgress); } - } else { - // The context value changed. Search for matching consumers and schedule - // them to update. - propagateContextChange(workInProgress, context, renderLanes); + + bubbleProperties(workInProgress); } + + return null; } } - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; + throw new Error( + "Unknown unit of work tag (" + + workInProgress.tag + + "). This error is likely caused by a bug in " + + "React. Please file an issue." + ); } -var hasWarnedAboutUsingContextAsConsumer = false; - -function updateContextConsumer(current, workInProgress, renderLanes) { - 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. - - { - if (context._context === undefined) { - // This may be because it's a Context (rather than a Consumer). - // Or it may be because it's older React where they're the same thing. - // We only want to warn if we're sure it's a new React. - if (context !== context.Consumer) { - if (!hasWarnedAboutUsingContextAsConsumer) { - hasWarnedAboutUsingContextAsConsumer = true; +function unwindWork(current, workInProgress, renderLanes) { + // Note: This intentionally doesn't check if we're hydrating because comparing + // to the current tree provider fiber is just as fast and less error-prone. + // Ideally we would have a special version of the work loop only + // for hydration. + popTreeContext(workInProgress); - error( - "Rendering directly is not supported and will be removed in " + - "a future major release. Did you mean to render instead?" - ); - } - } - } else { - context = context._context; - } - } + switch (workInProgress.tag) { + case ClassComponent: { + var Component = workInProgress.type; - var newProps = workInProgress.pendingProps; - var render = newProps.children; + if (isContextProvider(Component)) { + popContext(workInProgress); + } - { - if (typeof render !== "function") { - error( - "A context consumer was rendered with multiple children, or a child " + - "that isn't a function. A context consumer expects a single child " + - "that is a function. If you did pass a function, make sure there " + - "is no trailing or leading whitespace around it." - ); - } - } + var flags = workInProgress.flags; - prepareToReadContext(workInProgress, renderLanes); - var newValue = readContext(context); + if (flags & ShouldCapture) { + workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; - if (enableSchedulingProfiler) { - markComponentRenderStarted(workInProgress); - } + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } - var newChildren; + return workInProgress; + } - { - ReactCurrentOwner$2.current = workInProgress; - setIsRendering(true); - newChildren = render(newValue); - setIsRendering(false); - } + return null; + } - if (enableSchedulingProfiler) { - markComponentRenderStopped(); - } // React DevTools reads this flag. + case HostRoot: { + { + popCacheProvider(workInProgress); + } - workInProgress.flags |= PerformedWork; - reconcileChildren(current, workInProgress, newChildren, renderLanes); - return workInProgress.child; -} + if (enableTransitionTracing) { + popRootMarkerInstance(workInProgress); + } -function updateScopeComponent(current, workInProgress, renderLanes) { - var nextProps = workInProgress.pendingProps; - var nextChildren = nextProps.children; - reconcileChildren(current, workInProgress, nextChildren, renderLanes); - return workInProgress.child; -} + popRootTransition(workInProgress); + popHostContainer(workInProgress); + popTopLevelContextObject(workInProgress); + resetWorkInProgressVersions(); + var _flags = workInProgress.flags; -function markWorkInProgressReceivedUpdate() { - didReceiveUpdate = true; -} -function checkIfWorkInProgressReceivedUpdate() { - return didReceiveUpdate; -} + if ( + (_flags & ShouldCapture) !== NoFlags$1 && + (_flags & DidCapture) === NoFlags$1 + ) { + // There was an error during render that wasn't captured by a suspense + // boundary. Do a second pass on the root to unmount the children. + workInProgress.flags = (_flags & ~ShouldCapture) | DidCapture; + return workInProgress; + } // We unwound to the root without completing it. Exit. -function resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress) { - if ((workInProgress.mode & ConcurrentMode) === NoMode) { - if (current !== null) { - // A 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 + return null; + } - workInProgress.flags |= Placement; + case HostHoistable: + case HostSingleton: + case HostComponent: { + // TODO: popHydrationState + popHostContext(workInProgress); + return null; } - } -} -function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) { - if (current !== null) { - // Reuse previous dependencies - workInProgress.dependencies = current.dependencies; - } + case SuspenseComponent: { + popSuspenseHandler(workInProgress); + var suspenseState = workInProgress.memoizedState; - { - // Don't update "base" render times for bailouts. - stopProfilerTimerIfRunning(); - } + if (suspenseState !== null && suspenseState.dehydrated !== null) { + if (workInProgress.alternate === null) { + throw new Error( + "Threw in newly mounted dehydrated component. This is likely a bug in " + + "React. Please file an issue." + ); + } - markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work. + resetHydrationState(); + } - if (!includesSomeLane(renderLanes, workInProgress.childLanes)) { - // 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. - if (enableLazyContextPropagation && current !== null) { - // Before bailing out, check if there are any context changes in - // the children. - lazilyPropagateParentContextChanges(current, workInProgress, renderLanes); + var _flags2 = workInProgress.flags; - if (!includesSomeLane(renderLanes, workInProgress.childLanes)) { - return null; + if (_flags2 & ShouldCapture) { + workInProgress.flags = (_flags2 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } + + return workInProgress; } - } else { + return null; } - } // This fiber doesn't have work, but its subtree does. Clone the child - // fibers and continue. - cloneChildFibers(current, workInProgress); - return workInProgress.child; -} + case SuspenseListComponent: { + popSuspenseListContext(workInProgress); // SuspenseList doesn't actually catch anything. It should've been + // caught by a nested boundary. If not, it should bubble through. -function remountFiber(current, oldWorkInProgress, newWorkInProgress) { - { - var returnFiber = oldWorkInProgress.return; + return null; + } - if (returnFiber === null) { - // eslint-disable-next-line react-internal/prod-error-codes - throw new Error("Cannot swap the root fiber."); - } // Disconnect from the old current. - // It will get deleted. + case HostPortal: + popHostContainer(workInProgress); + return null; - current.alternate = null; - oldWorkInProgress.alternate = null; // Connect to the new tree. + case ContextProvider: + var context = workInProgress.type._context; + popProvider(context, workInProgress); + return null; - newWorkInProgress.index = oldWorkInProgress.index; - newWorkInProgress.sibling = oldWorkInProgress.sibling; - newWorkInProgress.return = oldWorkInProgress.return; - newWorkInProgress.ref = oldWorkInProgress.ref; // Replace the child/sibling pointers above it. + case OffscreenComponent: + case LegacyHiddenComponent: { + popSuspenseHandler(workInProgress); + popHiddenContext(workInProgress); + popTransition(workInProgress, current); + var _flags3 = workInProgress.flags; - if (oldWorkInProgress === returnFiber.child) { - returnFiber.child = newWorkInProgress; - } else { - var prevSibling = returnFiber.child; + if (_flags3 & ShouldCapture) { + workInProgress.flags = (_flags3 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. - if (prevSibling === null) { - // eslint-disable-next-line react-internal/prod-error-codes - throw new Error("Expected parent to have a child."); - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if ((workInProgress.mode & ProfileMode) !== NoMode) { + transferActualDuration(workInProgress); + } - while (prevSibling.sibling !== oldWorkInProgress) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - prevSibling = prevSibling.sibling; + return workInProgress; + } - if (prevSibling === null) { - // eslint-disable-next-line react-internal/prod-error-codes - throw new Error("Expected to find the previous sibling."); - } - } // $FlowFixMe[incompatible-use] found when upgrading Flow + return null; + } - prevSibling.sibling = newWorkInProgress; - } // Delete the old fiber and place the new one. - // Since the old fiber is disconnected, we have to schedule it manually. + case CacheComponent: + { + popCacheProvider(workInProgress); + } - var deletions = returnFiber.deletions; + return null; - if (deletions === null) { - returnFiber.deletions = [current]; - returnFiber.flags |= ChildDeletion; - } else { - deletions.push(current); - } + case TracingMarkerComponent: + if (enableTransitionTracing) { + if (workInProgress.stateNode !== null) { + popMarkerInstance(workInProgress); + } + } - newWorkInProgress.flags |= Placement; // Restart work from the new fiber. + return null; - return newWorkInProgress; + default: + return null; } } -function checkScheduledUpdateOrContext(current, renderLanes) { - // Before performing an early bailout, we must check if there are pending - // updates or context. - var updateLanes = current.lanes; +function unwindInterruptedWork(current, interruptedWork, renderLanes) { + // Note: This intentionally doesn't check if we're hydrating because comparing + // to the current tree provider fiber is just as fast and less error-prone. + // Ideally we would have a special version of the work loop only + // for hydration. + popTreeContext(interruptedWork); - if (includesSomeLane(updateLanes, renderLanes)) { - return true; - } // No pending update, but because context is propagated lazily, we need - // to check for a context change before we bail out. + switch (interruptedWork.tag) { + case ClassComponent: { + var childContextTypes = interruptedWork.type.childContextTypes; - if (enableLazyContextPropagation) { - var dependencies = current.dependencies; + if (childContextTypes !== null && childContextTypes !== undefined) { + popContext(interruptedWork); + } - if (dependencies !== null && checkIfContextChanged(dependencies)) { - return true; + break; } - } - - return false; -} - -function attemptEarlyBailoutIfNoScheduledUpdate( - current, - workInProgress, - renderLanes -) { - // 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); - pushRootTransition(workInProgress); - if (enableTransitionTracing) { - pushRootMarkerInstance(workInProgress); + case HostRoot: { + { + popCacheProvider(interruptedWork); } - { - var cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, cache); + if (enableTransitionTracing) { + popRootMarkerInstance(interruptedWork); } - resetHydrationState(); + popRootTransition(interruptedWork); + popHostContainer(interruptedWork); + popTopLevelContextObject(interruptedWork); + resetWorkInProgressVersions(); break; + } + case HostHoistable: case HostSingleton: - case HostComponent: - pushHostContext(workInProgress); + case HostComponent: { + popHostContext(interruptedWork); break; + } - case ClassComponent: { - var Component = workInProgress.type; + case HostPortal: + popHostContainer(interruptedWork); + break; - if (isContextProvider(Component)) { - pushContextProvider(workInProgress); - } + case SuspenseComponent: + popSuspenseHandler(interruptedWork); + break; + case SuspenseListComponent: + popSuspenseListContext(interruptedWork); break; - } - case HostPortal: - pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); + case ContextProvider: + var context = interruptedWork.type._context; + popProvider(context, interruptedWork); break; - case ContextProvider: { - var newValue = workInProgress.memoizedProps.value; - var context = workInProgress.type._context; - pushProvider(workInProgress, context, newValue); + case OffscreenComponent: + case LegacyHiddenComponent: + popSuspenseHandler(interruptedWork); + popHiddenContext(interruptedWork); + popTransition(interruptedWork, current); break; - } - case Profiler: + case CacheComponent: { - // Profiler should only call onRender when one of its descendants actually rendered. - var hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); + popCacheProvider(interruptedWork); + } - if (hasChildWork) { - workInProgress.flags |= Update; - } + break; - { - // Reset effect durations for the next eventual effect phase. - // These are reset during render to allow the DevTools commit hook a chance to read them, - var stateNode = workInProgress.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + case TracingMarkerComponent: + if (enableTransitionTracing) { + var instance = interruptedWork.stateNode; + + if (instance !== null) { + popMarkerInstance(interruptedWork); } } break; + } +} - case SuspenseComponent: { - var state = workInProgress.memoizedState; +// Provided by www +var ReactFbErrorUtils = require("ReactFbErrorUtils"); - if (state !== null) { - if (state.dehydrated !== null) { - // We're not going to render the children, so this is just to maintain - // push/pop symmetry - pushPrimaryTreeSuspenseHandler(workInProgress); // We know that this component will suspend again because if it has - // been unsuspended it has committed as a resolved Suspense component. - // If it needs to be retried, it should have work scheduled on it. +if (typeof ReactFbErrorUtils.invokeGuardedCallback !== "function") { + throw new Error( + "Expected ReactFbErrorUtils.invokeGuardedCallback to be a function." + ); +} + +function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { + // This will call `this.onError(err)` if an error was caught. + ReactFbErrorUtils.invokeGuardedCallback.apply(this, arguments); +} + +var hasError = false; +var caughtError = null; // Used by event system to capture/rethrow the first error. + +var hasRethrowError = false; +var rethrowError = null; +var reporter = { + onError: function (error) { + hasError = true; + caughtError = error; + } +}; +/** + * 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 + */ + +function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { + hasError = false; + caughtError = null; + invokeGuardedCallbackImpl.apply(reporter, arguments); +} +/** + * 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 + */ + +function invokeGuardedCallbackAndCatchFirstError( + name, + func, + context, + a, + b, + c, + d, + e, + f +) { + invokeGuardedCallback.apply(this, arguments); + + if (hasError) { + var error = clearCaughtError(); + + if (!hasRethrowError) { + hasRethrowError = true; + rethrowError = error; + } + } +} +/** + * During execution of guarded functions we will capture the first error which + * we will rethrow to be handled by the top level error handler. + */ + +function rethrowCaughtError() { + if (hasRethrowError) { + var error = rethrowError; + hasRethrowError = false; + rethrowError = null; + throw error; + } +} +function hasCaughtError() { + return hasError; +} +function clearCaughtError() { + if (hasError) { + var error = caughtError; + hasError = false; + caughtError = null; + return error; + } else { + throw new Error( + "clearCaughtError was called but no error was captured. This error " + + "is likely caused by a bug in React. Please file an issue." + ); + } +} + +var didWarnAboutUndefinedSnapshotBeforeUpdate = null; + +{ + didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); +} // Used during the commit phase to track the state of the Offscreen component stack. +// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor. + +var offscreenSubtreeIsHidden = false; +var offscreenSubtreeWasHidden = false; +var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; +var nextEffect = null; // Used for Profiling builds to track updaters. + +var inProgressLanes = null; +var inProgressRoot = null; + +function shouldProfile(current) { + return ( + (current.mode & ProfileMode) !== NoMode && + (getExecutionContext() & CommitContext) !== NoContext + ); +} + +function reportUncaughtErrorInDEV(error) { + // Wrapping each small part of the commit phase into a guarded + // callback is a bit too slow (https://github.com/facebook/react/pull/21666). + // But we rely on it to surface errors to DEV tools like overlays + // (https://github.com/facebook/react/issues/21712). + // As a compromise, rethrow only caught errors in a guard. + { + invokeGuardedCallback(null, function () { + throw error; + }); + clearCaughtError(); + } +} + +function callComponentWillUnmountWithTimer(current, instance) { + instance.props = current.memoizedProps; + instance.state = current.memoizedState; + + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + instance.componentWillUnmount(); + } finally { + recordLayoutEffectDuration(current); + } + } else { + instance.componentWillUnmount(); + } +} // Capture errors so they don't interrupt unmounting. - workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we - // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork. +function safelyCallComponentWillUnmount( + current, + nearestMountedAncestor, + instance +) { + try { + callComponentWillUnmountWithTimer(current, instance); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } +} // Capture errors so they don't interrupt mounting. - return null; - } // 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 - // child fragment. +function safelyAttachRef(current, nearestMountedAncestor) { + try { + commitAttachRef(current); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } +} - var primaryChildFragment = workInProgress.child; - var primaryChildLanes = primaryChildFragment.childLanes; +function safelyDetachRef(current, nearestMountedAncestor) { + var ref = current.ref; + var refCleanup = current.refCleanup; - if (includesSomeLane(renderLanes, primaryChildLanes)) { - // The primary children have pending work. Use the normal path - // to attempt to render the primary children again. - return updateSuspenseComponent(current, workInProgress, renderLanes); + if (ref !== null) { + if (typeof refCleanup === "function") { + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + refCleanup(); + } finally { + recordLayoutEffectDuration(current); + } } else { - // The primary child fragment does not have pending work marked - // on it - pushPrimaryTreeSuspenseHandler(workInProgress); // The primary children do not have pending work with sufficient - // priority. Bailout. + refCleanup(); + } + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } finally { + // `refCleanup` has been called. Nullify all references to it to prevent double invocation. + current.refCleanup = null; + var finishedWork = current.alternate; - var child = bailoutOnAlreadyFinishedWork( - current, - workInProgress, - renderLanes - ); + if (finishedWork != null) { + finishedWork.refCleanup = null; + } + } + } else if (typeof ref === "function") { + var retVal; - if (child !== null) { - // The fallback children have pending work. Skip over the - // primary children and work on the fallback. - return child.sibling; - } else { - // Note: We can return `null` here because we already checked - // whether there were nested context consumers, via the call to - // `bailoutOnAlreadyFinishedWork` above. - return null; + try { + if (shouldProfile(current)) { + try { + startLayoutEffectTimer(); + retVal = ref(null); + } finally { + recordLayoutEffectDuration(current); } + } else { + retVal = ref(null); } - } else { - pushPrimaryTreeSuspenseHandler(workInProgress); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); } - break; - } - - case SuspenseListComponent: { - var didSuspendBefore = (current.flags & DidCapture) !== NoFlags$1; - - var _hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); - - if (enableLazyContextPropagation && !_hasChildWork) { - // Context changes may not have been propagated yet. We need to do - // that now, before we can decide whether to bail out. - // TODO: We use `childLanes` as a heuristic for whether there is - // remaining work in a few places, including - // `bailoutOnAlreadyFinishedWork` and - // `updateDehydratedSuspenseComponent`. We should maybe extract this - // into a dedicated function. - lazilyPropagateParentContextChanges( - current, - workInProgress, - renderLanes - ); - _hasChildWork = includesSomeLane( - renderLanes, - workInProgress.childLanes - ); + { + if (typeof retVal === "function") { + error( + "Unexpected return value from a callback ref in %s. " + + "A callback ref should not return a function.", + getComponentNameFromFiber(current) + ); + } } + } else { + // $FlowFixMe unable to narrow type to RefObject + ref.current = null; + } + } +} - if (didSuspendBefore) { - if (_hasChildWork) { - // If something was in fallback state last time, and we have all the - // same children then we're still in progressive loading state. - // Something might get unblocked by state updates or retries in the - // tree which will affect the tail. So we need to use the normal - // path to compute the correct tail. - return updateSuspenseListComponent( - current, - workInProgress, - renderLanes - ); - } // If none of the children had any work, that means that none of - // them got retried so they'll still be blocked in the same way - // as before. We can fast bail out. +function safelyCallDestroy(current, nearestMountedAncestor, destroy) { + try { + destroy(); + } catch (error) { + captureCommitPhaseError(current, nearestMountedAncestor, error); + } +} - workInProgress.flags |= DidCapture; - } // If nothing suspended before and we're rendering the same children, - // then the tail doesn't matter. Anything new that suspends will work - // in the "together" mode, so we can continue from the state we had. +var focusedInstanceHandle = null; +var shouldFireAfterActiveInstanceBlur = false; +function commitBeforeMutationEffects(root, firstChild) { + focusedInstanceHandle = prepareForCommit(); + nextEffect = firstChild; + commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber - var renderState = workInProgress.memoizedState; + var shouldFire = shouldFireAfterActiveInstanceBlur; + shouldFireAfterActiveInstanceBlur = false; + focusedInstanceHandle = null; + return shouldFire; +} - if (renderState !== null) { - // Reset to the "together" mode in case we've started a different - // update in the past but didn't complete it. - renderState.rendering = null; - renderState.tail = null; - renderState.lastEffect = null; - } +function commitBeforeMutationEffects_begin() { + while (nextEffect !== null) { + var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. + // Let's skip the whole loop if it's off. - pushSuspenseListContext(workInProgress, suspenseStackCursor.current); + { + // TODO: Should wrap this in flags check, too, as optimization + var deletions = fiber.deletions; - if (_hasChildWork) { - break; - } else { - // If none of the children had any work, that means that none of - // them got retried so they'll still be blocked in the same way - // as before. We can fast bail out. - return null; + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var deletion = deletions[i]; + commitBeforeMutationEffectsDeletion(deletion); + } } } - case OffscreenComponent: - case LegacyHiddenComponent: { - // Need to check if the tree still needs to be deferred. This is - // almost identical to the logic used in the normal update path, - // so we'll just enter that. The only difference is we'll bail out - // at the next level instead of this one, because the child props - // have not changed. Which is fine. - // TODO: Probably should refactor `beginWork` to split the bailout - // path from the normal path. I'm tempted to do a labeled break here - // but I won't :) - workInProgress.lanes = NoLanes; - return updateOffscreenComponent(current, workInProgress, renderLanes); + var child = fiber.child; + + if ( + (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && + child !== null + ) { + child.return = fiber; + nextEffect = child; + } else { + commitBeforeMutationEffects_complete(); } + } +} - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - pushCacheProvider(workInProgress, _cache); - } +function commitBeforeMutationEffects_complete() { + while (nextEffect !== null) { + var fiber = nextEffect; + setCurrentFiber(fiber); - break; + try { + commitBeforeMutationEffectsOnFiber(fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } - case TracingMarkerComponent: { - if (enableTransitionTracing) { - var instance = workInProgress.stateNode; + resetCurrentFiber(); + var sibling = fiber.sibling; - if (instance !== null) { - pushMarkerInstance(workInProgress, instance); - } - } + if (sibling !== null) { + sibling.return = fiber.return; + nextEffect = sibling; + return; } - } - return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes); + nextEffect = fiber.return; + } } -function beginWork$1(current, workInProgress, renderLanes) { +function commitBeforeMutationEffectsOnFiber(finishedWork) { + var current = finishedWork.alternate; + var flags = finishedWork.flags; + { - if (workInProgress._debugNeedsRemount && current !== null) { - // This will restart the begin phase with a new fiber. - return remountFiber( - current, - workInProgress, - createFiberFromTypeAndProps( - workInProgress.type, - workInProgress.key, - workInProgress.pendingProps, - workInProgress._debugOwner || null, - workInProgress.mode, - workInProgress.lanes - ) - ); + if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) { + // Check to see if the focused element was inside of a hidden (Suspense) subtree. + // TODO: Move this out of the hot path using a dedicated effect tag. + if ( + finishedWork.tag === SuspenseComponent && + isSuspenseBoundaryBeingHidden(current, finishedWork) && // $FlowFixMe[incompatible-call] found when upgrading Flow + doesFiberContain(finishedWork, focusedInstanceHandle) + ) { + shouldFireAfterActiveInstanceBlur = true; + beforeActiveInstanceBlur(finishedWork); + } } } - if (current !== null) { - var oldProps = current.memoizedProps; - var newProps = workInProgress.pendingProps; - - if ( - oldProps !== newProps || - hasContextChanged() || // Force a re-render if the implementation changed due to hot reload: - workInProgress.type !== current.type - ) { - // 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 { - // Neither props nor legacy context changes. Check if there's a pending - // update or context change. - var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext( - current, - renderLanes - ); + if ((flags & Snapshot) !== NoFlags$1) { + setCurrentFiber(finishedWork); + } - if ( - !hasScheduledUpdateOrContext && // If this is the second pass of an error or suspense boundary, there - // may not be work scheduled on `current`, so we check for this flag. - (workInProgress.flags & DidCapture) === NoFlags$1 - ) { - // No pending updates or context. Bail out now. - didReceiveUpdate = false; - return attemptEarlyBailoutIfNoScheduledUpdate( - current, - workInProgress, - renderLanes - ); + switch (finishedWork.tag) { + case FunctionComponent: { + { + if ((flags & Update) !== NoFlags$1) { + commitUseEffectEventMount(finishedWork); + } } - if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags$1) { - // This is a special case that only exists for legacy mode. - // See https://github.com/facebook/react/pull/19216. - didReceiveUpdate = true; - } else { - // An update was scheduled on this fiber, but there are no new props - // nor legacy context. Set this to false. If an update queue or context - // consumer produces a changed value, it will set this to true. Otherwise, - // the component will assume the children have not changed and bail out. - didReceiveUpdate = false; - } + break; } - } else { - didReceiveUpdate = false; - if (getIsHydrating() && isForkedChild(workInProgress)) { - // Check if this child belongs to a list of muliple children in - // its parent. - // - // In a true multi-threaded implementation, we would render children on - // parallel threads. This would represent the beginning of a new render - // thread for this subtree. - // - // We only use this for id generation during hydration, which is why the - // logic is located in this special branch. - var slotIndex = workInProgress.index; - var numberOfForks = getForksAtLevel(); - pushTreeId(workInProgress, numberOfForks, slotIndex); + case ForwardRef: + case SimpleMemoComponent: { + break; } - } // Before entering the begin phase, clear pending update priority. - // TODO: This assumes that we're about to evaluate the component and process - // the update queue. However, there's an exception: SimpleMemoComponent - // sometimes bails out later in the begin phase. This indicates that we should - // move this assignment out of the common path and into each branch. - workInProgress.lanes = NoLanes; + case ClassComponent: { + if ((flags & Snapshot) !== NoFlags$1) { + if (current !== null) { + var prevProps = current.memoizedProps; + var prevState = current.memoizedState; + 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. - switch (workInProgress.tag) { - case IndeterminateComponent: { - return mountIndeterminateComponent( - current, - workInProgress, - workInProgress.type, - renderLanes - ); - } + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } - case LazyComponent: { - var elementType = workInProgress.elementType; - return mountLazyComponent( - current, - workInProgress, - elementType, - renderLanes - ); - } + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "getSnapshotBeforeUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } + } + } - case FunctionComponent: { - var Component = workInProgress.type; - var unresolvedProps = workInProgress.pendingProps; - var resolvedProps = - workInProgress.elementType === Component - ? unresolvedProps - : resolveDefaultProps(Component, unresolvedProps); - return updateFunctionComponent( - current, - workInProgress, - Component, - resolvedProps, - renderLanes - ); - } + var snapshot = instance.getSnapshotBeforeUpdate( + finishedWork.elementType === finishedWork.type + ? prevProps + : resolveDefaultProps(finishedWork.type, prevProps), + prevState + ); - case ClassComponent: { - var _Component = workInProgress.type; - var _unresolvedProps = workInProgress.pendingProps; + { + var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; - var _resolvedProps = - workInProgress.elementType === _Component - ? _unresolvedProps - : resolveDefaultProps(_Component, _unresolvedProps); + if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { + didWarnSet.add(finishedWork.type); - return updateClassComponent( - current, - workInProgress, - _Component, - _resolvedProps, - renderLanes - ); - } + error( + "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + + "must be returned. You have returned undefined.", + getComponentNameFromFiber(finishedWork) + ); + } + } - case HostRoot: - return updateHostRoot(current, workInProgress, renderLanes); + instance.__reactInternalSnapshotBeforeUpdate = snapshot; + } + } - case HostHoistable: { - return updateHostHoistable(current, workInProgress); + break; } - // eslint-disable-next-line no-fallthrough + case HostRoot: { + if ((flags & Snapshot) !== NoFlags$1) { + { + var root = finishedWork.stateNode; + clearContainer(root.containerInfo); + } + } - case HostSingleton: { - return updateHostSingleton(current, workInProgress, renderLanes); + break; } - // eslint-disable-next-line no-fallthrough - case HostComponent: - return updateHostComponent$1(current, workInProgress, renderLanes); - + case HostHoistable: + case HostSingleton: case HostText: - return updateHostText$1(current, workInProgress); + case HostPortal: + case IncompleteClassComponent: + // Nothing to do for these component types + break; + + default: { + if ((flags & Snapshot) !== NoFlags$1) { + throw new Error( + "This unit of work tag should not have side-effects. This error is " + + "likely caused by a bug in React. Please file an issue." + ); + } + } + } + + if ((flags & Snapshot) !== NoFlags$1) { + resetCurrentFiber(); + } +} + +function commitBeforeMutationEffectsDeletion(deletion) { + { + // TODO (effects) It would be nice to avoid calling doesFiberContain() + // Maybe we can repurpose one of the subtreeFlags positions for this instead? + // Use it to store which part of the tree the focused instance is in? + // This assumes we can safely determine that instance during the "render" phase. + if (doesFiberContain(deletion, focusedInstanceHandle)) { + shouldFireAfterActiveInstanceBlur = true; + beforeActiveInstanceBlur(deletion); + } + } +} - case SuspenseComponent: - return updateSuspenseComponent(current, workInProgress, renderLanes); +function commitHookEffectListUnmount( + flags, + finishedWork, + nearestMountedAncestor +) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - case HostPortal: - return updatePortalComponent(current, workInProgress, renderLanes); + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - case ForwardRef: { - var type = workInProgress.type; - var _unresolvedProps2 = workInProgress.pendingProps; + do { + if ((effect.tag & flags) === flags) { + // Unmount + var destroy = effect.destroy; + effect.destroy = undefined; - var _resolvedProps2 = - workInProgress.elementType === type - ? _unresolvedProps2 - : resolveDefaultProps(type, _unresolvedProps2); + if (destroy !== undefined) { + if (enableSchedulingProfiler) { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStarted(finishedWork); + } + } - return updateForwardRef( - current, - workInProgress, - type, - _resolvedProps2, - renderLanes - ); - } + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); + } + } - case Fragment: - return updateFragment(current, workInProgress, renderLanes); + safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); - case Mode: - return updateMode(current, workInProgress, renderLanes); + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); + } + } - case Profiler: - return updateProfiler(current, workInProgress, renderLanes); + if (enableSchedulingProfiler) { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectUnmountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectUnmountStopped(); + } + } + } + } - case ContextProvider: - return updateContextProvider(current, workInProgress, renderLanes); + effect = effect.next; + } while (effect !== firstEffect); + } +} - case ContextConsumer: - return updateContextConsumer(current, workInProgress, renderLanes); +function commitHookEffectListMount(flags, finishedWork) { + var updateQueue = finishedWork.updateQueue; + var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - case MemoComponent: { - var _type2 = workInProgress.type; - var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props. + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); + do { + if ((effect.tag & flags) === flags) { + if (enableSchedulingProfiler) { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStarted(finishedWork); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStarted(finishedWork); + } + } // Mount - { - if (workInProgress.type !== workInProgress.elementType) { - var outerPropTypes = _type2.propTypes; + var create = effect.create; - if (outerPropTypes) { - checkPropTypes( - outerPropTypes, - _resolvedProps3, // Resolved for outer only - "prop", - getComponentNameFromType(_type2) - ); + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(true); } } - } - _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); - return updateMemoComponent( - current, - workInProgress, - _type2, - _resolvedProps3, - renderLanes - ); - } + effect.destroy = create(); - case SimpleMemoComponent: { - return updateSimpleMemoComponent( - current, - workInProgress, - workInProgress.type, - workInProgress.pendingProps, - renderLanes - ); - } + { + if ((flags & Insertion) !== NoFlags) { + setIsRunningInsertionEffect(false); + } + } - case IncompleteClassComponent: { - var _Component2 = workInProgress.type; - var _unresolvedProps4 = workInProgress.pendingProps; + if (enableSchedulingProfiler) { + if ((flags & Passive) !== NoFlags) { + markComponentPassiveEffectMountStopped(); + } else if ((flags & Layout) !== NoFlags) { + markComponentLayoutEffectMountStopped(); + } + } - var _resolvedProps4 = - workInProgress.elementType === _Component2 - ? _unresolvedProps4 - : resolveDefaultProps(_Component2, _unresolvedProps4); + { + var destroy = effect.destroy; - return mountIncompleteClassComponent( - current, - workInProgress, - _Component2, - _resolvedProps4, - renderLanes - ); - } + if (destroy !== undefined && typeof destroy !== "function") { + var hookName = void 0; - case SuspenseListComponent: { - return updateSuspenseListComponent(current, workInProgress, renderLanes); - } + if ((effect.tag & Layout) !== NoFlags$1) { + hookName = "useLayoutEffect"; + } else if ((effect.tag & Insertion) !== NoFlags$1) { + hookName = "useInsertionEffect"; + } else { + hookName = "useEffect"; + } - case ScopeComponent: { - { - return updateScopeComponent(current, workInProgress, renderLanes); - } - } + var addendum = void 0; - case OffscreenComponent: { - return updateOffscreenComponent(current, workInProgress, renderLanes); - } + if (destroy === null) { + addendum = + " You returned null. If your effect does not require clean " + + "up, return undefined (or nothing)."; + } else if (typeof destroy.then === "function") { + addendum = + "\n\nIt looks like you wrote " + + hookName + + "(async () => ...) or returned a Promise. " + + "Instead, write the async function inside your effect " + + "and call it immediately:\n\n" + + hookName + + "(() => {\n" + + " async function fetchData() {\n" + + " // You can await here\n" + + " const response = await MyAPI.getData(someId);\n" + + " // ...\n" + + " }\n" + + " fetchData();\n" + + "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + + "Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching"; + } else { + addendum = " You returned: " + destroy; + } - case LegacyHiddenComponent: { - { - return updateLegacyHiddenComponent( - current, - workInProgress, - renderLanes - ); + error( + "%s must not return anything besides a function, " + + "which is used for clean-up.%s", + hookName, + addendum + ); + } + } } - } - case CacheComponent: { - { - return updateCacheComponent(current, workInProgress, renderLanes); - } - } + effect = effect.next; + } while (effect !== firstEffect); + } +} - case TracingMarkerComponent: { - if (enableTransitionTracing) { - return updateTracingMarkerComponent( - current, - workInProgress, - renderLanes - ); - } +function commitUseEffectEventMount(finishedWork) { + var updateQueue = finishedWork.updateQueue; + var eventPayloads = updateQueue !== null ? updateQueue.events : null; - break; + if (eventPayloads !== null) { + for (var ii = 0; ii < eventPayloads.length; ii++) { + var _eventPayloads$ii = eventPayloads[ii], + ref = _eventPayloads$ii.ref, + nextImpl = _eventPayloads$ii.nextImpl; + ref.impl = nextImpl; } } - - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); } -var valueCursor = createCursor(null); -var rendererCursorDEV; +function commitPassiveEffectDurations(finishedRoot, finishedWork) { + if (getExecutionContext() & CommitContext) { + // Only Profilers with work in their subtree will have an Update effect scheduled. + if ((finishedWork.flags & Update) !== NoFlags$1) { + switch (finishedWork.tag) { + case Profiler: { + var passiveEffectDuration = + finishedWork.stateNode.passiveEffectDuration; + var _finishedWork$memoize = finishedWork.memoizedProps, + id = _finishedWork$memoize.id, + onPostCommit = _finishedWork$memoize.onPostCommit; // This value will still reflect the previous commit phase. + // It does not get reset until the start of the next commit phase. -{ - rendererCursorDEV = createCursor(null); -} + var commitTime = getCommitTime(); + var phase = finishedWork.alternate === null ? "mount" : "update"; -var rendererSigil; + { + if (isCurrentUpdateNested()) { + phase = "nested-update"; + } + } -{ - // Use this to detect multiple renderers using the same context - rendererSigil = {}; -} + if (typeof onPostCommit === "function") { + onPostCommit(id, phase, passiveEffectDuration, commitTime); + } // Bubble times to the next nearest ancestor Profiler. + // After we process that Profiler, we'll bubble further up. -var currentlyRenderingFiber = null; -var lastContextDependency = null; -var lastFullyObservedContext = null; -var isDisallowedContextReadInDEV = false; -function resetContextDependencies() { - // This is called right before React yields execution, to ensure `readContext` - // cannot be called outside the render phase. - currentlyRenderingFiber = null; - lastContextDependency = null; - lastFullyObservedContext = null; + var parentFiber = finishedWork.return; - { - isDisallowedContextReadInDEV = false; - } -} -function enterDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = true; - } -} -function exitDisallowedContextReadInDEV() { - { - isDisallowedContextReadInDEV = false; - } -} -function pushProvider(providerFiber, context, nextValue) { - { - push(valueCursor, context._currentValue, providerFiber); - context._currentValue = nextValue; + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.passiveEffectDuration += passiveEffectDuration; + break outer; - { - push(rendererCursorDEV, context._currentRenderer, providerFiber); + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.passiveEffectDuration += passiveEffectDuration; + break outer; + } - if ( - context._currentRenderer !== undefined && - context._currentRenderer !== null && - context._currentRenderer !== rendererSigil - ) { - error( - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); - } + parentFiber = parentFiber.return; + } - context._currentRenderer = rendererSigil; + break; + } + } } } } -function popProvider(context, providerFiber) { - var currentValue = valueCursor.current; - { - if (currentValue === REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED) { - context._currentValue = context._defaultValue; - } else { - context._currentValue = currentValue; +function commitHookLayoutEffects(finishedWork, hookFlags) { + // At this point layout effects have already been destroyed (during mutation phase). + // This is done to prevent sibling component effects from interfering with each other, + // e.g. a destroy function in one component should never override a ref set + // by a create function in another component during the same commit. + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - { - var currentRenderer = rendererCursorDEV.current; - pop(rendererCursorDEV, providerFiber); - context._currentRenderer = currentRenderer; + recordLayoutEffectDuration(finishedWork); + } else { + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } } - - pop(valueCursor, providerFiber); } -function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) { - // Update the child lanes of all the ancestors, including the alternates. - var node = parent; - while (node !== null) { - var alternate = node.alternate; +function commitClassLayoutLifecycles(finishedWork, current) { + var instance = finishedWork.stateNode; - if (!isSubsetOfLanes(node.childLanes, renderLanes)) { - node.childLanes = mergeLanes(node.childLanes, renderLanes); + if (current === null) { + // 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. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } - if (alternate !== null) { - alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "componentDidMount. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } } - } else if ( - alternate !== null && - !isSubsetOfLanes(alternate.childLanes, renderLanes) - ) { - alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes); - } else; - - if (node === propagationRoot) { - break; } - node = node.return; - } + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - { - if (node !== propagationRoot) { - error( - "Expected to find the propagation root when scheduling context work. " + - "This error is likely caused by a bug in React. Please file an issue." - ); + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } - } -} -function propagateContextChange(workInProgress, context, renderLanes) { - if (enableLazyContextPropagation) { - // TODO: This path is only used by Cache components. Update - // lazilyPropagateParentContextChanges to look for Cache components so they - // can take advantage of lazy propagation. - var forcePropagateEntireTree = true; - propagateContextChanges( - workInProgress, - [context], - renderLanes, - forcePropagateEntireTree - ); } else { - propagateContextChange_eager(workInProgress, context, renderLanes); - } -} - -function propagateContextChange_eager(workInProgress, context, renderLanes) { - // Only used by eager implementation - if (enableLazyContextPropagation) { - return; - } - - var fiber = workInProgress.child; - - if (fiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - fiber.return = workInProgress; - } + var prevProps = + finishedWork.elementType === finishedWork.type + ? current.memoizedProps + : resolveDefaultProps(finishedWork.type, current.memoizedProps); + var prevState = current.memoizedState; // 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. - while (fiber !== null) { - var nextFiber = void 0; // Visit this fiber. + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } - var list = fiber.dependencies; + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "componentDidUpdate. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } + } + } - if (list !== null) { - nextFiber = fiber.child; - var dependency = list.firstContext; + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - while (dependency !== null) { - // Check if the context matches. - if (dependency.context === context) { - // Match! Schedule an update on this fiber. - if (fiber.tag === ClassComponent) { - // Schedule a force update on the work-in-progress. - var lane = pickArbitraryLane(renderLanes); - var update = createUpdate(lane); - 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. - // Inlined `enqueueUpdate` to remove interleaved update check + recordLayoutEffectDuration(finishedWork); + } else { + try { + instance.componentDidUpdate( + prevProps, + prevState, + instance.__reactInternalSnapshotBeforeUpdate + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } +} - var updateQueue = fiber.updateQueue; +function commitClassCallbacks(finishedWork) { + // TODO: I think this is now always non-null by the time it reaches the + // commit phase. Consider removing the type check. + var updateQueue = finishedWork.updateQueue; - if (updateQueue === null); - else { - var sharedQueue = updateQueue.shared; - var pending = sharedQueue.pending; + if (updateQueue !== null) { + var instance = finishedWork.stateNode; - if (pending === null) { - // This is the first update. Create a circular list. - update.next = update; - } else { - update.next = pending.next; - pending.next = update; - } + { + if ( + finishedWork.type === finishedWork.elementType && + !didWarnAboutReassigningProps + ) { + if (instance.props !== finishedWork.memoizedProps) { + error( + "Expected %s props to match memoized props before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.props`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } - sharedQueue.pending = update; - } - } + if (instance.state !== finishedWork.memoizedState) { + error( + "Expected %s state to match memoized state before " + + "processing the update queue. " + + "This might either be because of a bug in React, or because " + + "a component reassigns its own `this.state`. " + + "Please file an issue.", + getComponentNameFromFiber(finishedWork) || "instance" + ); + } + } + } // 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. - fiber.lanes = mergeLanes(fiber.lanes, renderLanes); - var alternate = fiber.alternate; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } +function commitHostComponentMount(finishedWork) { + var type = finishedWork.type; + var props = finishedWork.memoizedProps; + var instance = finishedWork.stateNode; - scheduleContextWorkOnParentPath( - fiber.return, - renderLanes, - workInProgress - ); // Mark the updated lanes on the list, too. + try { + commitMount(instance, type, props, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } +} - list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the - // dependency list. +function commitProfilerUpdate(finishedWork, current) { + if (getExecutionContext() & CommitContext) { + try { + var _finishedWork$memoize2 = finishedWork.memoizedProps, + onCommit = _finishedWork$memoize2.onCommit, + onRender = _finishedWork$memoize2.onRender; + var effectDuration = finishedWork.stateNode.effectDuration; + var commitTime = getCommitTime(); + var phase = current === null ? "mount" : "update"; - break; + if (enableProfilerNestedUpdatePhase) { + if (isCurrentUpdateNested()) { + phase = "nested-update"; } - - 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 (fiber.tag === DehydratedFragment) { - // If a dehydrated suspense boundary 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. - var parentSuspense = fiber.return; - if (parentSuspense === null) { - throw new Error( - "We just came from a parent so we must have had a parent. This is a bug in React." + if (typeof onRender === "function") { + onRender( + finishedWork.memoizedProps.id, + phase, + finishedWork.actualDuration, + finishedWork.treeBaseDuration, + finishedWork.actualStartTime, + commitTime ); } - parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); - var _alternate = parentSuspense.alternate; - - if (_alternate !== null) { - _alternate.lanes = mergeLanes(_alternate.lanes, renderLanes); - } // 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 childLanes on - // this fiber to indicate that a context has changed. - - scheduleContextWorkOnParentPath( - parentSuspense, - renderLanes, - workInProgress - ); - nextFiber = fiber.sibling; - } else { - // Traverse down. - nextFiber = fiber.child; - } + if (enableProfilerCommitHooks) { + if (typeof onCommit === "function") { + onCommit( + finishedWork.memoizedProps.id, + phase, + effectDuration, + commitTime + ); + } // Schedule a passive effect for this Profiler to call onPostCommit hooks. + // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, + // because the effect is also where times bubble to parent Profilers. - 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; + enqueuePendingPassiveProfilerEffect(finishedWork); // Propagate layout effect durations to the next nearest Profiler ancestor. + // Do not reset these values until the next render so DevTools has a chance to read them first. - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } + var parentFiber = finishedWork.return; - var sibling = nextFiber.sibling; + outer: while (parentFiber !== null) { + switch (parentFiber.tag) { + case HostRoot: + var root = parentFiber.stateNode; + root.effectDuration += effectDuration; + break outer; - 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. + case Profiler: + var parentStateNode = parentFiber.stateNode; + parentStateNode.effectDuration += effectDuration; + break outer; + } - nextFiber = nextFiber.return; + parentFiber = parentFiber.return; + } } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - - fiber = nextFiber; } } -function propagateContextChanges( - workInProgress, - contexts, - renderLanes, - forcePropagateEntireTree +function commitLayoutEffectOnFiber( + finishedRoot, + current, + finishedWork, + committedLanes ) { - // Only used by lazy implementation - if (!enableLazyContextPropagation) { - return; - } + // When updating this function, also update reappearLayoutEffects, which does + // most of the same things when an offscreen tree goes from hidden -> visible. + var flags = finishedWork.flags; - var fiber = workInProgress.child; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - if (fiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - fiber.return = workInProgress; - } + if (flags & Update) { + commitHookLayoutEffects(finishedWork, Layout | HasEffect); + } - while (fiber !== null) { - var nextFiber = void 0; // Visit this fiber. + break; + } - var list = fiber.dependencies; + case ClassComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - if (list !== null) { - nextFiber = fiber.child; - var dep = list.firstContext; + if (flags & Update) { + commitClassLayoutLifecycles(finishedWork, current); + } - findChangedDep: while (dep !== null) { - // Assigning these to constants to help Flow - var dependency = dep; - var consumer = fiber; + if (flags & Callback) { + commitClassCallbacks(finishedWork); + } - for (var i = 0; i < contexts.length; i++) { - var context = contexts[i]; // Check if the context matches. - // TODO: Compare selected values to bail out early. + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); + } - if (dependency.context === context) { - // Match! Schedule an update on this fiber. - // In the lazy implementation, don't mark a dirty flag on the - // dependency itself. Not all changes are propagated, so we can't - // rely on the propagation function alone to determine whether - // something has changed; the consumer will check. In the future, we - // could add back a dirty flag as an optimization to avoid double - // checking, but until we have selectors it's not really worth - // the trouble. - consumer.lanes = mergeLanes(consumer.lanes, renderLanes); - var alternate = consumer.alternate; + break; + } - if (alternate !== null) { - alternate.lanes = mergeLanes(alternate.lanes, renderLanes); - } + case HostRoot: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - scheduleContextWorkOnParentPath( - consumer.return, - renderLanes, - workInProgress - ); + if (flags & Callback) { + // TODO: I think this is now always non-null by the time it reaches the + // commit phase. Consider removing the type check. + var updateQueue = finishedWork.updateQueue; - if (!forcePropagateEntireTree) { - // During lazy propagation, when we find a match, we can defer - // propagating changes to the children, because we're going to - // visit them during render. We should continue propagating the - // siblings, though - nextFiber = null; - } // Since we already found a match, we can stop traversing the - // dependency list. + if (updateQueue !== null) { + var instance = null; - break findChangedDep; + if (finishedWork.child !== null) { + switch (finishedWork.child.tag) { + case HostSingleton: + case HostComponent: + instance = getPublicInstance(finishedWork.child.stateNode); + break; + + case ClassComponent: + instance = finishedWork.child.stateNode; + break; + } } - } - dep = dependency.next; + try { + commitCallbacks(updateQueue, instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } } - } else if (fiber.tag === DehydratedFragment) { - // If a dehydrated suspense boundary 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. - var parentSuspense = fiber.return; - if (parentSuspense === null) { - throw new Error( - "We just came from a parent so we must have had a parent. This is a bug in React." - ); + break; + } + + case HostHoistable: { + { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); + } + + break; } + } + // eslint-disable-next-line-no-fallthrough - parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes); - var _alternate2 = parentSuspense.alternate; + case HostSingleton: + case HostComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // 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 (_alternate2 !== null) { - _alternate2.lanes = mergeLanes(_alternate2.lanes, renderLanes); - } // 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 childLanes on - // this fiber to indicate that a context has changed. + if (current === null && flags & Update) { + commitHostComponentMount(finishedWork); + } - scheduleContextWorkOnParentPath( - parentSuspense, - renderLanes, - workInProgress - ); - nextFiber = null; - } else { - // Traverse down. - nextFiber = fiber.child; + if (flags & Ref) { + safelyAttachRef(finishedWork, finishedWork.return); + } + + break; } - 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; + case Profiler: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // TODO: Should this fire inside an offscreen tree? Or should it wait to + // fire when the tree becomes visible again. - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } + if (flags & Update) { + commitProfilerUpdate(finishedWork, current); + } - var sibling = nextFiber.sibling; + break; + } - 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. + case SuspenseComponent: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - nextFiber = nextFiber.return; + if (flags & Update) { + commitSuspenseHydrationCallbacks(finishedRoot, finishedWork); } + + break; } - fiber = nextFiber; - } -} + case OffscreenComponent: { + var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; -function lazilyPropagateParentContextChanges( - current, - workInProgress, - renderLanes -) { - var forcePropagateEntireTree = false; - propagateParentContextChanges( - current, - workInProgress, - renderLanes, - forcePropagateEntireTree - ); -} // Used for propagating a deferred tree (Suspense, Offscreen). We must propagate -// to the entire subtree, because we won't revisit it until after the current -// render has completed, at which point we'll have lost track of which providers -// have changed. + if (isModernRoot) { + var isHidden = finishedWork.memoizedState !== null; + var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; -function propagateParentContextChangesToDeferredTree( - current, - workInProgress, - renderLanes -) { - var forcePropagateEntireTree = true; - propagateParentContextChanges( - current, - workInProgress, - renderLanes, - forcePropagateEntireTree - ); -} + if (newOffscreenSubtreeIsHidden); + else { + // The Offscreen tree is visible. + var wasHidden = current !== null && current.memoizedState !== null; + var newOffscreenSubtreeWasHidden = + wasHidden || offscreenSubtreeWasHidden; + var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; + var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden; -function propagateParentContextChanges( - current, - workInProgress, - renderLanes, - forcePropagateEntireTree -) { - if (!enableLazyContextPropagation) { - return; - } // Collect all the parent providers that changed. Since this is usually small - // number, we use an Array instead of Set. + if (offscreenSubtreeWasHidden && !prevOffscreenSubtreeWasHidden) { + // This is the root of a reappearing boundary. As we continue + // traversing the layout effects, we must also re-mount layout + // effects that were unmounted when the Offscreen subtree was + // hidden. So this is a superset of the normal commitLayoutEffects. + var includeWorkInProgressEffects = + (finishedWork.subtreeFlags & LayoutMask) !== NoFlags$1; + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); + } else { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + } - var contexts = null; - var parent = workInProgress; - var isInsidePropagationBailout = false; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + } + } else { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + } + + if (flags & Ref) { + var props = finishedWork.memoizedProps; - while (parent !== null) { - if (!isInsidePropagationBailout) { - if ((parent.flags & NeedsPropagation) !== NoFlags$1) { - isInsidePropagationBailout = true; - } else if ((parent.flags & DidPropagateContext) !== NoFlags$1) { - break; + if (props.mode === "manual") { + safelyAttachRef(finishedWork, finishedWork.return); + } else { + safelyDetachRef(finishedWork, finishedWork.return); + } } + + break; } - if (parent.tag === ContextProvider) { - var currentParent = parent.alternate; + default: { + recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + break; + } + } +} - if (currentParent === null) { - throw new Error("Should have a current fiber. This is a bug in React."); - } +function abortRootTransitions( + root, + abort, + deletedTransitions, + deletedOffscreenInstance, + isInDeletedTree +) { + if (enableTransitionTracing) { + var rootTransitions = root.incompleteTransitions; + deletedTransitions.forEach(function (transition) { + if (rootTransitions.has(transition)) { + var transitionInstance = rootTransitions.get(transition); - var oldProps = currentParent.memoizedProps; + if (transitionInstance.aborts === null) { + transitionInstance.aborts = []; + } - if (oldProps !== null) { - var providerType = parent.type; - var context = providerType._context; - var newProps = parent.pendingProps; - var newValue = newProps.value; - var oldValue = oldProps.value; + transitionInstance.aborts.push(abort); - if (!objectIs(newValue, oldValue)) { - if (contexts !== null) { - contexts.push(context); - } else { - contexts = [context]; + if (deletedOffscreenInstance !== null) { + if ( + transitionInstance.pendingBoundaries !== null && + transitionInstance.pendingBoundaries.has(deletedOffscreenInstance) + ) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + transitionInstance.pendingBoundaries.delete( + deletedOffscreenInstance + ); } } } - } - - parent = parent.return; + }); } - - if (contexts !== null) { - // If there were any changed providers, search through the children and - // propagate their changes. - propagateContextChanges( - workInProgress, - contexts, - renderLanes, - forcePropagateEntireTree - ); - } // This is an optimization so that we only propagate once per subtree. If a - // deeply nested child bails out, and it calls this propagation function, it - // uses this flag to know that the remaining ancestor providers have already - // been propagated. - // - // NOTE: This optimization is only necessary because we sometimes enter the - // begin phase of nodes that don't have any work scheduled on them — - // specifically, the siblings of a node that _does_ have scheduled work. The - // siblings will bail out and call this function again, even though we already - // propagated content changes to it and its subtree. So we use this flag to - // mark that the parent providers already propagated. - // - // Unfortunately, though, we need to ignore this flag when we're inside a - // tree whose context propagation was deferred — that's what the - // `NeedsPropagation` flag is for. - // - // If we could instead bail out before entering the siblings' begin phase, - // then we could remove both `DidPropagateContext` and `NeedsPropagation`. - // Consider this as part of the next refactor to the fiber tree structure. - - workInProgress.flags |= DidPropagateContext; } -function checkIfContextChanged(currentDependencies) { - if (!enableLazyContextPropagation) { - return false; - } // Iterate over the current dependencies to see if something changed. This - // only gets called if props and state has already bailed out, so it's a - // relatively uncommon path, except at the root of a changed subtree. - // Alternatively, we could move these comparisons into `readContext`, but - // that's a much hotter path, so I think this is an appropriate trade off. - - var dependency = currentDependencies.firstContext; +function abortTracingMarkerTransitions( + abortedFiber, + abort, + deletedTransitions, + deletedOffscreenInstance, + isInDeletedTree +) { + if (enableTransitionTracing) { + var markerInstance = abortedFiber.stateNode; + var markerTransitions = markerInstance.transitions; + var pendingBoundaries = markerInstance.pendingBoundaries; - while (dependency !== null) { - var context = dependency.context; - var newValue = context._currentValue; - var oldValue = dependency.memoizedValue; + if (markerTransitions !== null) { + // TODO: Refactor this code. Is there a way to move this code to + // the deletions phase instead of calculating it here while making sure + // complete is called appropriately? + deletedTransitions.forEach(function (transition) { + // If one of the transitions on the tracing marker is a transition + // that was in an aborted subtree, we will abort that tracing marker + if ( + abortedFiber !== null && + markerTransitions.has(transition) && + (markerInstance.aborts === null || + !markerInstance.aborts.includes(abort)) + ) { + if (markerInstance.transitions !== null) { + if (markerInstance.aborts === null) { + markerInstance.aborts = [abort]; + addMarkerIncompleteCallbackToPendingTransition( + abortedFiber.memoizedProps.name, + markerInstance.transitions, + markerInstance.aborts + ); + } else { + markerInstance.aborts.push(abort); + } // We only want to call onTransitionProgress when the marker hasn't been + // deleted - if (!objectIs(newValue, oldValue)) { - return true; + if ( + deletedOffscreenInstance !== null && + !isInDeletedTree && + pendingBoundaries !== null && + pendingBoundaries.has(deletedOffscreenInstance) + ) { + pendingBoundaries.delete(deletedOffscreenInstance); + addMarkerProgressCallbackToPendingTransition( + abortedFiber.memoizedProps.name, + deletedTransitions, + pendingBoundaries + ); + } + } + } + }); } - - dependency = dependency.next; } - - return false; } -function prepareToReadContext(workInProgress, renderLanes) { - currentlyRenderingFiber = workInProgress; - lastContextDependency = null; - lastFullyObservedContext = null; - var dependencies = workInProgress.dependencies; - if (dependencies !== null) { - if (enableLazyContextPropagation) { - // Reset the work-in-progress list - dependencies.firstContext = null; - } else { - var firstContext = dependencies.firstContext; +function abortParentMarkerTransitionsForDeletedFiber( + abortedFiber, + abort, + deletedTransitions, + deletedOffscreenInstance, + isInDeletedTree +) { + if (enableTransitionTracing) { + // Find all pending markers that are waiting on child suspense boundaries in the + // aborted subtree and cancels them + var fiber = abortedFiber; - if (firstContext !== null) { - if (includesSomeLane(dependencies.lanes, renderLanes)) { - // Context list has a pending update. Mark that this fiber performed work. - markWorkInProgressReceivedUpdate(); - } // Reset the work-in-progress list + while (fiber !== null) { + switch (fiber.tag) { + case TracingMarkerComponent: + abortTracingMarkerTransitions( + fiber, + abort, + deletedTransitions, + deletedOffscreenInstance, + isInDeletedTree + ); + break; - dependencies.firstContext = null; + case HostRoot: + var root = fiber.stateNode; + abortRootTransitions( + root, + abort, + deletedTransitions, + deletedOffscreenInstance + ); + break; } - } - } -} -function readContext(context) { - { - // This warning would fire if you read context inside a Hook like useMemo. - // Unlike the class check below, it's not enforced in production for perf. - if (isDisallowedContextReadInDEV) { - error( - "Context can only be read while React is rendering. " + - "In classes, you can read it in the render method or getDerivedStateFromProps. " + - "In function components, you can read it directly in the function body, but not " + - "inside Hooks like useReducer() or useMemo()." - ); - } - } - return readContextForConsumer(currentlyRenderingFiber, context); -} -function readContextDuringReconcilation(consumer, context, renderLanes) { - if (currentlyRenderingFiber === null) { - prepareToReadContext(consumer, renderLanes); + fiber = fiber.return; + } } - - return readContextForConsumer(consumer, context); } -function readContextForConsumer(consumer, context) { - var value = context._currentValue; +function commitTransitionProgress(offscreenFiber) { + if (enableTransitionTracing) { + // This function adds suspense boundaries to the root + // or tracing marker's pendingBoundaries map. + // When a suspense boundary goes from a resolved to a fallback + // state we add the boundary to the map, and when it goes from + // a fallback to a resolved state, we remove the boundary from + // the map. + // We use stateNode on the Offscreen component as a stable object + // that doesnt change from render to render. This way we can + // distinguish between different Offscreen instances (vs. the same + // Offscreen instance with different fibers) + var offscreenInstance = offscreenFiber.stateNode; + var prevState = null; + var previousFiber = offscreenFiber.alternate; - if (lastFullyObservedContext === context); - else { - var contextItem = { - context: context, - memoizedValue: value, - next: null - }; + if (previousFiber !== null && previousFiber.memoizedState !== null) { + prevState = previousFiber.memoizedState; + } - if (lastContextDependency === null) { - if (consumer === null) { - throw new Error( - "Context can only be read while React is rendering. " + - "In classes, you can read it in the render method or getDerivedStateFromProps. " + - "In function components, you can read it directly in the function body, but not " + - "inside Hooks like useReducer() or useMemo()." - ); - } // This is the first dependency for this component. Create a new list. + var nextState = offscreenFiber.memoizedState; + var wasHidden = prevState !== null; + var isHidden = nextState !== null; + var pendingMarkers = offscreenInstance._pendingMarkers; // If there is a name on the suspense boundary, store that in + // the pending boundaries. - lastContextDependency = contextItem; - consumer.dependencies = { - lanes: NoLanes, - firstContext: contextItem - }; + var name = null; + var parent = offscreenFiber.return; - if (enableLazyContextPropagation) { - consumer.flags |= NeedsPropagation; - } - } else { - // Append a new context item. - lastContextDependency = lastContextDependency.next = contextItem; + if ( + parent !== null && + parent.tag === SuspenseComponent && + parent.memoizedProps.unstable_name + ) { + name = parent.memoizedProps.unstable_name; } - } - return value; -} + if (!wasHidden && isHidden) { + // The suspense boundaries was just hidden. Add the boundary + // to the pending boundary set if it's there + if (pendingMarkers !== null) { + pendingMarkers.forEach(function (markerInstance) { + var pendingBoundaries = markerInstance.pendingBoundaries; + var transitions = markerInstance.transitions; + var markerName = markerInstance.name; -// replace it with a lightweight shim that only has the features we use. + if ( + pendingBoundaries !== null && + !pendingBoundaries.has(offscreenInstance) + ) { + pendingBoundaries.set(offscreenInstance, { + name: name + }); -var AbortControllerLocal = - typeof AbortController !== "undefined" - ? AbortController // $FlowFixMe[missing-this-annot] - : function AbortControllerShim() { - var listeners = []; - var signal = (this.signal = { - aborted: false, - addEventListener: function (type, listener) { - listeners.push(listener); + if (transitions !== null) { + if ( + markerInstance.tag === TransitionTracingMarker && + markerName !== null + ) { + addMarkerProgressCallbackToPendingTransition( + markerName, + transitions, + pendingBoundaries + ); + } else if (markerInstance.tag === TransitionRoot) { + transitions.forEach(function (transition) { + addTransitionProgressCallbackToPendingTransition( + transition, + pendingBoundaries + ); + }); + } + } } }); + } + } else if (wasHidden && !isHidden) { + // The suspense boundary went from hidden to visible. Remove + // the boundary from the pending suspense boundaries set + // if it's there + if (pendingMarkers !== null) { + pendingMarkers.forEach(function (markerInstance) { + var pendingBoundaries = markerInstance.pendingBoundaries; + var transitions = markerInstance.transitions; + var markerName = markerInstance.name; - this.abort = function () { - signal.aborted = true; - listeners.forEach(function (listener) { - return listener(); - }); - }; - }; // Intentionally not named imports because Rollup would -// use dynamic dispatch for CommonJS interop named imports. + if ( + pendingBoundaries !== null && + pendingBoundaries.has(offscreenInstance) + ) { + pendingBoundaries.delete(offscreenInstance); -var scheduleCallback$1 = Scheduler.unstable_scheduleCallback, - NormalPriority = Scheduler.unstable_NormalPriority; -var CacheContext = { - $$typeof: REACT_CONTEXT_TYPE, - // We don't use Consumer/Provider for Cache components. So we'll cheat. - Consumer: null, - Provider: null, - // We'll initialize these at the root. - _currentValue: null, - _currentValue2: null, - _threadCount: 0, - _defaultValue: null, - _globalName: null -}; + if (transitions !== null) { + if ( + markerInstance.tag === TransitionTracingMarker && + markerName !== null + ) { + addMarkerProgressCallbackToPendingTransition( + markerName, + transitions, + pendingBoundaries + ); // If there are no more unresolved suspense boundaries, the interaction + // is considered finished -{ - CacheContext._currentRenderer = null; - CacheContext._currentRenderer2 = null; -} // Creates a new empty Cache instance with a ref-count of 0. The caller is responsible -// for retaining the cache once it is in use (retainCache), and releasing the cache -// once it is no longer needed (releaseCache). + if (pendingBoundaries.size === 0) { + if (markerInstance.aborts === null) { + addMarkerCompleteCallbackToPendingTransition( + markerName, + transitions + ); + } -function createCache() { - var cache = { - controller: new AbortControllerLocal(), - data: new Map(), - refCount: 0 - }; - return cache; -} -function retainCache(cache) { - { - if (cache.controller.signal.aborted) { - warn( - "A cache instance was retained after it was already freed. " + - "This likely indicates a bug in React." - ); + markerInstance.transitions = null; + markerInstance.pendingBoundaries = null; + markerInstance.aborts = null; + } + } else if (markerInstance.tag === TransitionRoot) { + transitions.forEach(function (transition) { + addTransitionProgressCallbackToPendingTransition( + transition, + pendingBoundaries + ); + }); + } + } + } + }); + } } } +} - cache.refCount++; -} // Cleanup a cache instance, potentially freeing it if there are no more references - -function releaseCache(cache) { - cache.refCount--; +function hideOrUnhideAllChildren(finishedWork, isHidden) { + // Only hide or unhide the top-most host nodes. + var hostSubtreeRoot = null; { - if (cache.refCount < 0) { - warn( - "A cache instance was released after it was already freed. " + - "This likely indicates a bug in React." - ); - } - } + // 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; - if (cache.refCount === 0) { - scheduleCallback$1(NormalPriority, function () { - cache.controller.abort(); - }); - } -} -function pushCacheProvider(workInProgress, cache) { - pushProvider(workInProgress, CacheContext, cache); -} -function popCacheProvider(workInProgress, cache) { - popProvider(CacheContext, workInProgress); -} + while (true) { + if ( + node.tag === HostComponent || + node.tag === HostHoistable || + node.tag === HostSingleton + ) { + if (hostSubtreeRoot === null) { + hostSubtreeRoot = node; -var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig; -var NoTransition = null; -function requestCurrentTransition() { - return ReactCurrentBatchConfig$1.transition; -} // When retrying a Suspense/Offscreen boundary, we restore the cache that was -// used during the previous render by placing it here, on the stack. + try { + var instance = node.stateNode; + + if (isHidden) { + hideInstance(instance); + } else { + unhideInstance(node.stateNode, node.memoizedProps); + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } else if (node.tag === HostText) { + if (hostSubtreeRoot === null) { + try { + var _instance = node.stateNode; + + if (isHidden) { + hideTextInstance(_instance); + } else { + unhideTextInstance(_instance, node.memoizedProps); + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } + } else if ( + (node.tag === OffscreenComponent || + node.tag === LegacyHiddenComponent) && + node.memoizedState !== null && + node !== finishedWork + ); + else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; + } -var resumedCache = createCursor(null); // During the render/synchronous commit phase, we don't actually process the -// transitions. Therefore, we want to lazily combine transitions. Instead of -// comparing the arrays of transitions when we combine them and storing them -// and filtering out the duplicates, we will instead store the unprocessed transitions -// in an array and actually filter them in the passive phase. + if (node === finishedWork) { + return; + } -var transitionStack = createCursor(null); + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return; + } -function peekCacheFromPool() { - // If we're rendering inside a Suspense boundary that is currently hidden, - // we should use the same cache that we used during the previous render, if - // one exists. + if (hostSubtreeRoot === node) { + hostSubtreeRoot = null; + } - var cacheResumedFromPreviousRender = resumedCache.current; + node = node.return; + } - if (cacheResumedFromPreviousRender !== null) { - return cacheResumedFromPreviousRender; - } // Otherwise, check the root's cache pool. + if (hostSubtreeRoot === node) { + hostSubtreeRoot = null; + } - var root = getWorkInProgressRoot(); - var cacheFromRootCachePool = root.pooledCache; - return cacheFromRootCachePool; + node.sibling.return = node.return; + node = node.sibling; + } + } } -function requestCacheFromPool(renderLanes) { - // Similar to previous function, except if there's not already a cache in the - // pool, we allocate a new one. - var cacheFromPool = peekCacheFromPool(); +function commitAttachRef(finishedWork) { + var ref = finishedWork.ref; - if (cacheFromPool !== null) { - return cacheFromPool; - } // Create a fresh cache and add it to the root cache pool. A cache can have - // multiple owners: - // - A cache pool that lives on the FiberRoot. This is where all fresh caches - // are originally created (TODO: except during refreshes, until we implement - // this correctly). The root takes ownership immediately when the cache is - // created. Conceptually, root.pooledCache is an Option> (owned), - // and the return value of this function is a &Arc (borrowed). - // - One of several fiber types: host root, cache boundary, suspense - // component. These retain and release in the commit phase. + if (ref !== null) { + var instance = finishedWork.stateNode; + var instanceToUse; - var root = getWorkInProgressRoot(); - var freshCache = createCache(); - root.pooledCache = freshCache; - retainCache(freshCache); + switch (finishedWork.tag) { + case HostHoistable: + case HostSingleton: + case HostComponent: + instanceToUse = getPublicInstance(instance); + break; - if (freshCache !== null) { - root.pooledCacheLanes |= renderLanes; - } + default: + instanceToUse = instance; + } // Moved outside to ensure DCE works with this flag - return freshCache; -} -function pushRootTransition(workInProgress, root, renderLanes) { - if (enableTransitionTracing) { - var rootTransitions = getWorkInProgressTransitions(); - push(transitionStack, rootTransitions, workInProgress); - } -} -function popRootTransition(workInProgress, root, renderLanes) { - if (enableTransitionTracing) { - pop(transitionStack, workInProgress); - } -} -function pushTransition( - offscreenWorkInProgress, - prevCachePool, - newTransitions -) { - { - if (prevCachePool === null) { - push(resumedCache, resumedCache.current, offscreenWorkInProgress); - } else { - push(resumedCache, prevCachePool.pool, offscreenWorkInProgress); + if (finishedWork.tag === ScopeComponent) { + instanceToUse = instance; } - } - if (enableTransitionTracing) { - if (transitionStack.current === null) { - push(transitionStack, newTransitions, offscreenWorkInProgress); - } else if (newTransitions === null) { - push(transitionStack, transitionStack.current, offscreenWorkInProgress); + if (typeof ref === "function") { + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + finishedWork.refCleanup = ref(instanceToUse); + } finally { + recordLayoutEffectDuration(finishedWork); + } + } else { + finishedWork.refCleanup = ref(instanceToUse); + } } else { - push( - transitionStack, - transitionStack.current.concat(newTransitions), - offscreenWorkInProgress - ); - } - } -} -function popTransition(workInProgress, current) { - if (current !== null) { - if (enableTransitionTracing) { - pop(transitionStack, workInProgress); - } + { + if (!ref.hasOwnProperty("current")) { + error( + "Unexpected ref object provided for %s. " + + "Use either a ref-setter function or React.createRef().", + getComponentNameFromFiber(finishedWork) + ); + } + } // $FlowFixMe unable to narrow type to the non-function case - { - pop(resumedCache, workInProgress); + ref.current = instanceToUse; } } } -function getPendingTransitions() { - if (!enableTransitionTracing) { - return null; + +function detachFiberMutation(fiber) { + // Cut off the return pointer to disconnect it from the tree. + // This enables us to detect and warn against state updates on an unmounted component. + // It also prevents events from bubbling from within disconnected components. + // + // Ideally, we should also 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. + // + // Note that we can't clear child or sibling pointers yet. + // They're needed for passive effects and for findDOMNode. + // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects). + // + // Don't reset the alternate yet, either. We need that so we can detach the + // alternate's fields in the passive phase. Clearing the return pointer is + // sufficient for findDOMNode semantics. + var alternate = fiber.alternate; + + if (alternate !== null) { + alternate.return = null; } - return transitionStack.current; + fiber.return = null; } -function getSuspendedCache() { - // cache that would have been used to render fresh data during this render, - // if there was any, so that we can resume rendering with the same cache when - // we receive more data. - var cacheFromPool = peekCacheFromPool(); +function detachFiberAfterEffects(fiber) { + var alternate = fiber.alternate; - if (cacheFromPool === null) { - return null; + if (alternate !== null) { + fiber.alternate = null; + detachFiberAfterEffects(alternate); + } // Clear cyclical Fiber fields. This level alone is designed to roughly + // approximate the planned Fiber refactor. In that world, `setState` will be + // bound to a special "instance" object instead of a Fiber. The Instance + // object will not have any of these fields. It will only be connected to + // the fiber tree via a single link at the root. So if this level alone is + // sufficient to fix memory issues, that bodes well for our plans. + + fiber.child = null; + fiber.deletions = null; + fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host + // tree, which has its own pointers to children, parents, and siblings. + // The other host nodes also point back to fibers, so we should detach that + // one, too. + + if (fiber.tag === HostComponent) { + var hostInstance = fiber.stateNode; + + if (hostInstance !== null) { + detachDeletedInstance(hostInstance); + } } - return { - // We must also save the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue, - pool: cacheFromPool - }; + fiber.stateNode = null; + + { + fiber._debugOwner = null; + } // Theoretically, nothing in here should be necessary, because we already + // disconnected the fiber from the tree. So even if something leaks this + // particular fiber, it won't leak anything else. + + fiber.return = null; + fiber.dependencies = null; + fiber.memoizedProps = null; + fiber.memoizedState = null; + fiber.pendingProps = null; + fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead. + + fiber.updateQueue = null; } -function getOffscreenDeferredCache() { - var cacheFromPool = peekCacheFromPool(); - if (cacheFromPool === null) { - return null; +function getHostParentFiber(fiber) { + var parent = fiber.return; + + while (parent !== null) { + if (isHostParent(parent)) { + return parent; + } + + parent = parent.return; } - return { - // We must also store the parent, so that when we resume we can detect - // a refresh. - parent: CacheContext._currentValue, - pool: cacheFromPool - }; + throw new Error( + "Expected to find a host parent. This error is likely caused by a bug " + + "in React. Please file an issue." + ); } -function getSuspenseFallbackChild(fiber) { - return fiber.child.sibling.child; +function isHostParent(fiber) { + return ( + fiber.tag === HostComponent || + fiber.tag === HostRoot || + fiber.tag === HostHoistable || + fiber.tag === HostSingleton || + fiber.tag === HostPortal + ); } -var emptyObject = {}; +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. + // TODO: Find a more efficient way to do this. + var node = fiber; -function collectScopedNodes(node, fn, scopedNodes) { - { - if (node.tag === HostComponent) { - var type = node.type, - memoizedProps = node.memoizedProps, - stateNode = node.stateNode; - var instance = getPublicInstance(stateNode); + 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; + } // $FlowFixMe[incompatible-type] found when upgrading Flow - if ( - instance !== null && - fn(type, memoizedProps || emptyObject, instance) === true - ) { - scopedNodes.push(instance); - } + node = node.return; } - var child = node.child; + node.sibling.return = node.return; + node = node.sibling; - if (isFiberSuspenseAndTimedOut(node)) { - child = getSuspenseFallbackChild(node); - } + while ( + node.tag !== HostComponent && + node.tag !== HostText && + node.tag !== HostSingleton && + node.tag !== DehydratedFragment + ) { + // 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.flags & 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 (child !== null) { - collectScopedNodesFromChildren(child, fn, scopedNodes); + 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.flags & Placement)) { + // Found it! + return node.stateNode; } } } -function collectFirstScopedNode(node, fn) { +function commitPlacement(finishedWork) { { - if (node.tag === HostComponent) { - var type = node.type, - memoizedProps = node.memoizedProps, - stateNode = node.stateNode; - var instance = getPublicInstance(stateNode); + if (finishedWork.tag === HostSingleton) { + // Singletons are already in the Host and don't need to be placed + // Since they operate somewhat like Portals though their children will + // have Placement and will get placed inside them + return; + } + } // Recursively insert all host nodes into the parent. - if (instance !== null && fn(type, memoizedProps, instance) === true) { - return instance; + var parentFiber = getHostParentFiber(finishedWork); + + switch (parentFiber.tag) { + case HostSingleton: { + { + var parent = parentFiber.stateNode; + 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. + + insertOrAppendPlacementNode(finishedWork, before, parent); + break; } } + // eslint-disable-next-line no-fallthrough - var child = node.child; + case HostComponent: { + var _parent = parentFiber.stateNode; - if (isFiberSuspenseAndTimedOut(node)) { - child = getSuspenseFallbackChild(node); + if (parentFiber.flags & ContentReset) { + // Reset the text content of the parent before doing any insertions + resetTextContent(_parent); // Clear ContentReset from the effect tag + + parentFiber.flags &= ~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. + + insertOrAppendPlacementNode(finishedWork, _before, _parent); + break; } - if (child !== null) { - return collectFirstScopedNodeFromChildren(child, fn); + case HostRoot: + case HostPortal: { + var _parent2 = parentFiber.stateNode.containerInfo; + + var _before2 = getHostSibling(finishedWork); + + insertOrAppendPlacementNodeIntoContainer( + finishedWork, + _before2, + _parent2 + ); + break; } - } + // eslint-disable-next-line-no-fallthrough - return null; + default: + throw new Error( + "Invalid host parent fiber. This error is likely caused by a bug " + + "in React. Please file an issue." + ); + } } -function collectScopedNodesFromChildren(startingChild, fn, scopedNodes) { - var child = startingChild; +function insertOrAppendPlacementNodeIntoContainer(node, before, parent) { + var tag = node.tag; + var isHost = tag === HostComponent || tag === HostText; - while (child !== null) { - collectScopedNodes(child, fn, scopedNodes); - child = child.sibling; + if (isHost) { + var stateNode = node.stateNode; + + if (before) { + insertInContainerBefore(parent, stateNode, before); + } else { + appendChildToContainer(parent, stateNode); + } + } else if (tag === HostPortal || tag === HostSingleton); + else { + var child = node.child; + + if (child !== null) { + insertOrAppendPlacementNodeIntoContainer(child, before, parent); + var sibling = child.sibling; + + while (sibling !== null) { + insertOrAppendPlacementNodeIntoContainer(sibling, before, parent); + sibling = sibling.sibling; + } + } } } -function collectFirstScopedNodeFromChildren(startingChild, fn) { - var child = startingChild; +function insertOrAppendPlacementNode(node, before, parent) { + var tag = node.tag; + var isHost = tag === HostComponent || tag === HostText; - while (child !== null) { - var scopedNode = collectFirstScopedNode(child, fn); + if (isHost) { + var stateNode = node.stateNode; - if (scopedNode !== null) { - return scopedNode; + if (before) { + insertBefore(parent, stateNode, before); + } else { + appendChild(parent, stateNode); } + } else if (tag === HostPortal || tag === HostSingleton); + else { + var child = node.child; - child = child.sibling; + if (child !== null) { + insertOrAppendPlacementNode(child, before, parent); + var sibling = child.sibling; + + while (sibling !== null) { + insertOrAppendPlacementNode(sibling, before, parent); + sibling = sibling.sibling; + } + } } +} // These are tracked on the stack as we recursively traverse a +// deleted subtree. +// TODO: Update these during the whole mutation phase, not just during +// a deletion. - return null; -} +var hostParent = null; +var hostParentIsContainer = false; -function collectNearestContextValues(node, context, childContextValues) { - if (node.tag === ContextProvider && node.type._context === context) { - var contextValue = node.memoizedProps.value; - childContextValues.push(contextValue); - } else { - var child = node.child; +function commitDeletionEffects(root, returnFiber, deletedFiber) { + { + // We only have the top Fiber that was deleted but we need to recurse down its + // children to find all the terminal nodes. + // Recursively delete all host nodes from the parent, detach refs, clean + // up mounted layout effects, and call componentWillUnmount. + // We only need to remove the topmost host child in each branch. But then we + // still need to keep traversing to unmount effects, refs, and cWU. TODO: We + // could split this into two separate traversals functions, where the second + // one doesn't include any removeChild logic. This is maybe the same + // function as "disappearLayoutEffects" (or whatever that turns into after + // the layout phase is refactored to use recursion). + // Before starting, find the nearest host parent on the stack so we know + // which instance/container to remove the children from. + // TODO: Instead of searching up the fiber return path on every deletion, we + // can track the nearest host component on the JS stack as we traverse the + // tree during the commit phase. This would make insertions faster, too. + var parent = returnFiber; - if (isFiberSuspenseAndTimedOut(node)) { - child = getSuspenseFallbackChild(node); + findParent: while (parent !== null) { + switch (parent.tag) { + case HostSingleton: + case HostComponent: { + hostParent = parent.stateNode; + hostParentIsContainer = false; + break findParent; + } + + case HostRoot: { + hostParent = parent.stateNode.containerInfo; + hostParentIsContainer = true; + break findParent; + } + + case HostPortal: { + hostParent = parent.stateNode.containerInfo; + hostParentIsContainer = true; + break findParent; + } + } + + parent = parent.return; } - if (child !== null) { - collectNearestChildContextValues(child, context, childContextValues); + if (hostParent === null) { + throw new Error( + "Expected to find a host parent. This error is likely caused by " + + "a bug in React. Please file an issue." + ); } + + commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); + hostParent = null; + hostParentIsContainer = false; } + + detachFiberMutation(deletedFiber); } -function collectNearestChildContextValues( - startingChild, - context, - childContextValues +function recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + parent ) { - var child = startingChild; + // TODO: Use a static flag to skip trees that don't have unmount effects + var child = parent.child; while (child !== null) { - collectNearestContextValues(child, context, childContextValues); + commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child); child = child.sibling; } } -function DO_NOT_USE_queryAllNodes(fn) { - var currentFiber = getInstanceFromScope(this); +function commitDeletionEffectsOnFiber( + finishedRoot, + nearestMountedAncestor, + deletedFiber +) { + onCommitUnmount(deletedFiber); // The cases in this outer switch modify the stack before they traverse + // into their subtree. There are simpler cases in the inner switch + // that don't modify the stack. - if (currentFiber === null) { - return null; - } + switch (deletedFiber.tag) { + case HostHoistable: { + { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } - var child = currentFiber.child; - var scopedNodes = []; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); - if (child !== null) { - collectScopedNodesFromChildren(child, fn, scopedNodes); - } + if (deletedFiber.memoizedState) { + releaseResource(deletedFiber.memoizedState); + } else if (deletedFiber.stateNode) { + unmountHoistable(deletedFiber.stateNode); + } - return scopedNodes.length === 0 ? null : scopedNodes; -} + return; + } + } + // eslint-disable-next-line no-fallthrough -function DO_NOT_USE_queryFirstNode(fn) { - var currentFiber = getInstanceFromScope(this); + case HostSingleton: { + { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } - if (currentFiber === null) { - return null; - } + var prevHostParent = hostParent; + var prevHostParentIsContainer = hostParentIsContainer; + hostParent = deletedFiber.stateNode; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); // Normally this is called in passive unmount effect phase however with + // HostSingleton we warn if you acquire one that is already associated to + // a different fiber. To increase our chances of avoiding this, specifically + // if you keyed a HostSingleton so there will be a delete followed by a Placement + // we treat detach eagerly here - var child = currentFiber.child; + releaseSingletonInstance(deletedFiber.stateNode); + hostParent = prevHostParent; + hostParentIsContainer = prevHostParentIsContainer; + return; + } + } + // eslint-disable-next-line no-fallthrough - if (child !== null) { - return collectFirstScopedNodeFromChildren(child, fn); - } + case HostComponent: { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } // Intentional fallthrough to next branch + } + // eslint-disable-next-line-no-fallthrough - return null; -} + case HostText: { + // We only need to remove the nearest host child. Set the host parent + // to `null` on the stack to indicate that nested children don't + // need to be removed. + { + var _prevHostParent = hostParent; + var _prevHostParentIsContainer = hostParentIsContainer; + hostParent = null; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + hostParent = _prevHostParent; + hostParentIsContainer = _prevHostParentIsContainer; -function containsNode(node) { - var fiber = getInstanceFromNode$1(node); + if (hostParent !== null) { + // Now that all the child effects have unmounted, we can remove the + // node from the tree. + if (hostParentIsContainer) { + removeChildFromContainer(hostParent, deletedFiber.stateNode); + } else { + removeChild(hostParent, deletedFiber.stateNode); + } + } + } - while (fiber !== null) { - if (fiber.tag === ScopeComponent && fiber.stateNode === this) { - return true; + return; } - fiber = fiber.return; - } - - return false; -} - -function getChildContextValues(context) { - var currentFiber = getInstanceFromScope(this); + case DehydratedFragment: { + { + var hydrationCallbacks = finishedRoot.hydrationCallbacks; - if (currentFiber === null) { - return []; - } + if (hydrationCallbacks !== null) { + var onDeleted = hydrationCallbacks.onDeleted; - var child = currentFiber.child; - var childContextValues = []; + if (onDeleted) { + onDeleted(deletedFiber.stateNode); + } + } + } // Dehydrated fragments don't have any children + // Delete the dehydrated suspense boundary and all of its content. - if (child !== null) { - collectNearestChildContextValues(child, context, childContextValues); - } + { + if (hostParent !== null) { + if (hostParentIsContainer) { + clearSuspenseBoundaryFromContainer( + hostParent, + deletedFiber.stateNode + ); + } else { + clearSuspenseBoundary(hostParent, deletedFiber.stateNode); + } + } + } - return childContextValues; -} + return; + } -function createScopeInstance() { - return { - DO_NOT_USE_queryAllNodes: DO_NOT_USE_queryAllNodes, - DO_NOT_USE_queryFirstNode: DO_NOT_USE_queryFirstNode, - containsNode: containsNode, - getChildContextValues: getChildContextValues - }; -} + case HostPortal: { + { + // When we go into a portal, it becomes the parent to remove from. + var _prevHostParent2 = hostParent; + var _prevHostParentIsContainer2 = hostParentIsContainer; + hostParent = deletedFiber.stateNode.containerInfo; + hostParentIsContainer = true; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + hostParent = _prevHostParent2; + hostParentIsContainer = _prevHostParentIsContainer2; + } -function markUpdate(workInProgress) { - // Tag the fiber with an update effect. This turns a Placement into - // a PlacementAndUpdate. - workInProgress.flags |= Update; -} + return; + } -function markRef(workInProgress) { - workInProgress.flags |= Ref | RefStatic; -} + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + if (!offscreenSubtreeWasHidden) { + var updateQueue = deletedFiber.updateQueue; -function appendAllChildren( - 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; + if (updateQueue !== null) { + var lastEffect = updateQueue.lastEffect; - while (node !== null) { - if (node.tag === HostComponent || node.tag === HostText) { - appendInitialChild(parent, node.stateNode); - } else if (node.tag === HostPortal || node.tag === HostSingleton); - else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + if (lastEffect !== null) { + var firstEffect = lastEffect.next; + var effect = firstEffect; - if (node === workInProgress) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + do { + var _effect = effect, + destroy = _effect.destroy, + tag = _effect.tag; - while (node.sibling === null) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - if (node.return === null || node.return === workInProgress) { - return; - } + if (destroy !== undefined) { + if ((tag & Insertion) !== NoFlags) { + safelyCallDestroy( + deletedFiber, + nearestMountedAncestor, + destroy + ); + } else if ((tag & Layout) !== NoFlags) { + if (enableSchedulingProfiler) { + markComponentLayoutEffectUnmountStarted(deletedFiber); + } - node = node.return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + if (shouldProfile(deletedFiber)) { + startLayoutEffectTimer(); + safelyCallDestroy( + deletedFiber, + nearestMountedAncestor, + destroy + ); + recordLayoutEffectDuration(deletedFiber); + } else { + safelyCallDestroy( + deletedFiber, + nearestMountedAncestor, + destroy + ); + } - node.sibling.return = node.return; - node = node.sibling; - } - } -} // An unfortunate fork of appendAllChildren because we have two different parent types. + if (enableSchedulingProfiler) { + markComponentLayoutEffectUnmountStopped(); + } + } + } -function updateHostComponent(current, workInProgress, type, newProps) { - { - // 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; + effect = effect.next; + } while (effect !== firstEffect); + } + } + } - if (oldProps === newProps) { - // In mutation mode, this is sufficient for a bailout because - // we won't touch this node even if children changed. + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); 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, - 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. + case ClassComponent: { + if (!offscreenSubtreeWasHidden) { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + var instance = deletedFiber.stateNode; - if (updatePayload) { - markUpdate(workInProgress); - } - } -} + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount( + deletedFiber, + nearestMountedAncestor, + instance + ); + } + } -function updateHostText(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); + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + return; } - } -} - -function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) { - if (getIsHydrating()) { - // If we're hydrating, we should consume as many items as we can - // so we don't leave any behind. - return; - } - switch (renderState.tailMode) { - case "hidden": { - // Any insertions at the end of the tail list after this point - // should be invisible. If there are already mounted boundaries - // anything before them are not considered for collapsing. - // Therefore we need to go through the whole tail to find if - // there are any. - var tailNode = renderState.tail; - var lastTailNode = null; + case ScopeComponent: { + { + safelyDetachRef(deletedFiber, nearestMountedAncestor); + } - while (tailNode !== null) { - if (tailNode.alternate !== null) { - lastTailNode = tailNode; - } + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + return; + } - tailNode = tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + case OffscreenComponent: { + safelyDetachRef(deletedFiber, nearestMountedAncestor); - if (lastTailNode === null) { - // All remaining items in the tail are insertions. - renderState.tail = null; + if (deletedFiber.mode & ConcurrentMode) { + // If this offscreen component is hidden, we already unmounted it. Before + // deleting the children, track that it's already unmounted so that we + // don't attempt to unmount the effects again. + // TODO: If the tree is hidden, in most cases we should be able to skip + // over the nested children entirely. An exception is we haven't yet found + // the topmost host node to delete, which we already track on the stack. + // But the other case is portals, which need to be detached no matter how + // deeply they are nested. We should use a subtree flag to track whether a + // subtree includes a nested portal. + var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + offscreenSubtreeWasHidden = + prevOffscreenSubtreeWasHidden || deletedFiber.memoizedState !== null; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; } else { - // Detach the insertion after the last node that was already - // inserted. - lastTailNode.sibling = null; + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); } break; } - case "collapsed": { - // Any insertions at the end of the tail list after this point - // should be invisible. If there are already mounted boundaries - // anything before them are not considered for collapsing. - // Therefore we need to go through the whole tail to find if - // there are any. - var _tailNode = renderState.tail; - var _lastTailNode = null; + default: { + recursivelyTraverseDeletionEffects( + finishedRoot, + nearestMountedAncestor, + deletedFiber + ); + return; + } + } +} - while (_tailNode !== null) { - if (_tailNode.alternate !== null) { - _lastTailNode = _tailNode; - } +function commitSuspenseCallback(finishedWork) { + // TODO: Move this to passive phase + var newState = finishedWork.memoizedState; - _tailNode = _tailNode.sibling; - } // Next we're simply going to delete all insertions after the - // last rendered item. + if (newState !== null) { + var suspenseCallback = finishedWork.memoizedProps.suspenseCallback; - if (_lastTailNode === null) { - // All remaining items in the tail are insertions. - if (!hasRenderedATailFallback && renderState.tail !== null) { - // We suspended during the head. We want to show at least one - // row at the tail. So we'll keep on and cut off the rest. - renderState.tail.sibling = null; - } else { - renderState.tail = null; - } - } else { - // Detach the insertion after the last node that was already - // inserted. - _lastTailNode.sibling = null; - } + if (typeof suspenseCallback === "function") { + var wakeables = finishedWork.updateQueue; - break; + if (wakeables !== null) { + suspenseCallback(new Set(wakeables)); + } + } else { + if (suspenseCallback !== undefined) { + error("Unexpected type for suspenseCallback."); + } } } } -function bubbleProperties(completedWork) { - var didBailout = - completedWork.alternate !== null && - completedWork.alternate.child === completedWork.child; - var newChildLanes = NoLanes; - var subtreeFlags = NoFlags$1; +function commitSuspenseHydrationCallbacks(finishedRoot, finishedWork) { + var newState = finishedWork.memoizedState; - if (!didBailout) { - // Bubble up the earliest expiration time. - if ((completedWork.mode & ProfileMode) !== NoMode) { - // In profiling mode, resetChildExpirationTime is also used to reset - // profiler durations. - var actualDuration = completedWork.actualDuration; - var treeBaseDuration = completedWork.selfBaseDuration; - var child = completedWork.child; + if (newState === null) { + var current = finishedWork.alternate; - while (child !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(child.lanes, child.childLanes) - ); - subtreeFlags |= child.subtreeFlags; - subtreeFlags |= child.flags; // 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. - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + if (current !== null) { + var prevState = current.memoizedState; - actualDuration += child.actualDuration; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + if (prevState !== null) { + var suspenseInstance = prevState.dehydrated; - treeBaseDuration += child.treeBaseDuration; - child = child.sibling; - } + if (suspenseInstance !== null) { + try { + commitHydratedSuspenseInstance(suspenseInstance); - completedWork.actualDuration = actualDuration; - completedWork.treeBaseDuration = treeBaseDuration; - } else { - var _child = completedWork.child; + if (enableSuspenseCallback) { + var hydrationCallbacks = finishedRoot.hydrationCallbacks; - while (_child !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(_child.lanes, _child.childLanes) - ); - subtreeFlags |= _child.subtreeFlags; - subtreeFlags |= _child.flags; // Update the return pointer so the tree is consistent. This is a code - // smell because it assumes the commit phase is never concurrent with - // the render phase. Will address during refactor to alternate model. + if (hydrationCallbacks !== null) { + var onHydrated = hydrationCallbacks.onHydrated; - _child.return = completedWork; - _child = _child.sibling; + if (onHydrated) { + onHydrated(suspenseInstance); + } + } + } + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } } } + } +} - completedWork.subtreeFlags |= subtreeFlags; - } else { - // Bubble up the earliest expiration time. - if ((completedWork.mode & ProfileMode) !== NoMode) { - // In profiling mode, resetChildExpirationTime is also used to reset - // profiler durations. - var _treeBaseDuration = completedWork.selfBaseDuration; - var _child2 = completedWork.child; - - while (_child2 !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(_child2.lanes, _child2.childLanes) - ); // "Static" flags share the lifetime of the fiber/hook they belong to, - // so we should bubble those up even during a bailout. All the other - // flags have a lifetime only of a single render + commit, so we should - // ignore them. - - subtreeFlags |= _child2.subtreeFlags & StaticMask; - subtreeFlags |= _child2.flags & StaticMask; // $FlowFixMe[unsafe-addition] addition with possible null/undefined value +function getRetryCache(finishedWork) { + // TODO: Unify the interface for the retry cache so we don't have to switch + // on the tag like this. + switch (finishedWork.tag) { + case SuspenseComponent: + case SuspenseListComponent: { + var retryCache = finishedWork.stateNode; - _treeBaseDuration += _child2.treeBaseDuration; - _child2 = _child2.sibling; + if (retryCache === null) { + retryCache = finishedWork.stateNode = new PossiblyWeakSet(); } - completedWork.treeBaseDuration = _treeBaseDuration; - } else { - var _child3 = completedWork.child; - - while (_child3 !== null) { - newChildLanes = mergeLanes( - newChildLanes, - mergeLanes(_child3.lanes, _child3.childLanes) - ); // "Static" flags share the lifetime of the fiber/hook they belong to, - // so we should bubble those up even during a bailout. All the other - // flags have a lifetime only of a single render + commit, so we should - // ignore them. + return retryCache; + } - subtreeFlags |= _child3.subtreeFlags & StaticMask; - subtreeFlags |= _child3.flags & StaticMask; // Update the return pointer so the tree is consistent. This is a code - // smell because it assumes the commit phase is never concurrent with - // the render phase. Will address during refactor to alternate model. + case OffscreenComponent: { + var instance = finishedWork.stateNode; + var _retryCache = instance._retryCache; - _child3.return = completedWork; - _child3 = _child3.sibling; + if (_retryCache === null) { + _retryCache = instance._retryCache = new PossiblyWeakSet(); } + + return _retryCache; } - completedWork.subtreeFlags |= subtreeFlags; + default: { + throw new Error( + "Unexpected Suspense handler tag (" + + finishedWork.tag + + "). This is a " + + "bug in React." + ); + } } +} - completedWork.childLanes = newChildLanes; - return didBailout; +function detachOffscreenInstance(instance) { + var fiber = instance._current; + + if (fiber === null) { + throw new Error( + "Calling Offscreen.detach before instance handle has been set." + ); + } + + if ((instance._pendingVisibility & OffscreenDetached) !== NoFlags$1) { + // The instance is already detached, this is a noop. + return; + } // TODO: There is an opportunity to optimise this by not entering commit phase + // and unmounting effects directly. + + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + instance._pendingVisibility |= OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } } +function attachOffscreenInstance(instance) { + var fiber = instance._current; -function completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState -) { - if ( - hasUnhydratedTailNodes() && - (workInProgress.mode & ConcurrentMode) !== NoMode && - (workInProgress.flags & DidCapture) === NoFlags$1 - ) { - warnIfUnhydratedTailNodes(workInProgress); - resetHydrationState(); - workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture; - return false; + if (fiber === null) { + throw new Error( + "Calling Offscreen.detach before instance handle has been set." + ); } - var wasHydrated = popHydrationState(workInProgress); + if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { + // The instance is already attached, this is a noop. + return; + } - if (nextState !== null && nextState.dehydrated !== null) { - // We might be inside a hydration state the first time we're picking up this - // Suspense boundary, and also after we've reentered it for further hydration. - if (current === null) { - if (!wasHydrated) { - throw new Error( - "A dehydrated suspense component was completed without a hydrated node. " + - "This is probably a bug in React." - ); - } + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - prepareToHydrateHostSuspenseInstance(workInProgress); - bubbleProperties(workInProgress); + if (root !== null) { + instance._pendingVisibility &= ~OffscreenDetached; + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } +} - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var isTimedOutSuspense = nextState !== null; +function attachSuspenseRetryListeners(finishedWork, wakeables) { + // If this boundary just timed out, then it will have a set of wakeables. + // For each wakeable, attach a listener so that when it resolves, React + // attempts to re-render the boundary in the primary (pre-timeout) state. + var retryCache = getRetryCache(finishedWork); + wakeables.forEach(function (wakeable) { + // Memoize using the boundary fiber to prevent redundant listeners. + var retry = resolveRetryWakeable.bind(null, finishedWork, wakeable); - if (isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var primaryChildFragment = workInProgress.child; + if (!retryCache.has(wakeable)) { + retryCache.add(wakeable); - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } + { + if (isDevToolsPresent) { + if (inProgressLanes !== null && inProgressRoot !== null) { + // If we have pending work still, associate the original updaters with it. + restorePendingUpdaters(inProgressRoot, inProgressLanes); + } else { + throw Error( + "Expected finished root and lanes to be set. This is a bug in React." + ); } } } - return false; - } else { - // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration - // state since we're now exiting out of it. popHydrationState doesn't do that for us. - resetHydrationState(); + wakeable.then(retry, retry); + } + }); +} // This function detects when a Suspense boundary goes from visible to hidden. +// It returns false if the boundary is already hidden. +// TODO: Use an effect tag. - if ((workInProgress.flags & DidCapture) === NoFlags$1) { - // This boundary did not suspend so it's now hydrated and unsuspended. - workInProgress.memoizedState = null; - } // If nothing suspended, we need to schedule an effect to mark this boundary - // as having hydrated so events know that they're free to be invoked. - // It's also a signal to replay events and the suspense callback. - // If something suspended, schedule an effect to attach retry listeners. - // So we might as well always mark this. +function isSuspenseBoundaryBeingHidden(current, finishedWork) { + if (current !== null) { + var oldState = current.memoizedState; - workInProgress.flags |= Update; - bubbleProperties(workInProgress); + if (oldState === null || oldState.dehydrated !== null) { + var newState = finishedWork.memoizedState; + return newState !== null && newState.dehydrated === null; + } + } - { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - var _isTimedOutSuspense = nextState !== null; + return false; +} +function commitMutationEffects(root, finishedWork, committedLanes) { + inProgressLanes = committedLanes; + inProgressRoot = root; + setCurrentFiber(finishedWork); + commitMutationEffectsOnFiber(finishedWork, root); + setCurrentFiber(finishedWork); + inProgressLanes = null; + inProgressRoot = null; +} - if (_isTimedOutSuspense) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var _primaryChildFragment = workInProgress.child; +function recursivelyTraverseMutationEffects(root, parentFiber, lanes) { + // Deletions effects can be scheduled on any fiber type. They need to happen + // before the children effects hae fired. + var deletions = parentFiber.deletions; - if (_primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - _primaryChildFragment.treeBaseDuration; - } - } - } - } + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; - return false; + try { + commitDeletionEffects(root, parentFiber, childToDelete); + } catch (error) { + captureCommitPhaseError(childToDelete, parentFiber, error); + } } - } else { - // Successfully completed this tree. If this was a forced client render, - // there may have been recoverable errors during first hydration - // attempt. If so, add them to a queue so we can log them in the - // commit phase. - upgradeHydrationErrorsToRecoverable(); // Fall through to normal Suspense path + } - return true; + var prevDebugFiber = getCurrentFiber(); + + if (parentFiber.subtreeFlags & MutationMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + commitMutationEffectsOnFiber(child, root); + child = child.sibling; + } } + + setCurrentFiber(prevDebugFiber); } -function completeWork(current, workInProgress, renderLanes) { - var newProps = workInProgress.pendingProps; // Note: This intentionally doesn't check if we're hydrating because comparing - // to the current tree provider fiber is just as fast and less error-prone. - // Ideally we would have a special version of the work loop only - // for hydration. +var currentHoistableRoot = null; - popTreeContext(workInProgress); +function commitMutationEffectsOnFiber(finishedWork, root, lanes) { + var current = finishedWork.alternate; + var flags = finishedWork.flags; // The effect flag should be checked *after* we refine the type of fiber, + // because the fiber tag is more specific. An exception is any flag related + // to reconciliation, because those can be set on all fiber types. - switch (workInProgress.tag) { - case IndeterminateComponent: - case LazyComponent: - case SimpleMemoComponent: + switch (finishedWork.tag) { case FunctionComponent: case ForwardRef: - case Fragment: - case Mode: - case Profiler: - case ContextConsumer: case MemoComponent: - bubbleProperties(workInProgress); - return null; - - case ClassComponent: { - var Component = workInProgress.type; - - if (isContextProvider(Component)) { - popContext(workInProgress); - } - - bubbleProperties(workInProgress); - return null; - } + case SimpleMemoComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - case HostRoot: { - var fiberRoot = workInProgress.stateNode; + if (flags & Update) { + try { + commitHookEffectListUnmount( + Insertion | HasEffect, + finishedWork, + finishedWork.return + ); + commitHookEffectListMount(Insertion | HasEffect, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } // Layout effects are destroyed during the mutation phase so that all + // destroy functions for all fibers are called before any create functions. + // This prevents sibling component effects from interfering with each other, + // e.g. a destroy function in one component should never override a ref set + // by a create function in another component during the same commit. - if (enableTransitionTracing) { - var transitions = getWorkInProgressTransitions(); // We set the Passive flag here because if there are new transitions, - // we will need to schedule callbacks and process the transitions, - // which we do in the passive phase + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListUnmount( + Layout | HasEffect, + finishedWork, + finishedWork.return + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - if (transitions !== null) { - workInProgress.flags |= Passive$1; + recordLayoutEffectDuration(finishedWork); + } else { + try { + commitHookEffectListUnmount( + Layout | HasEffect, + finishedWork, + finishedWork.return + ); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } } } - { - var previousCache = null; + return; + } + + case ClassComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + if (flags & Ref) { if (current !== null) { - previousCache = current.memoizedState.cache; + safelyDetachRef(current, current.return); } + } - var cache = workInProgress.memoizedState.cache; + if (flags & Callback && offscreenSubtreeIsHidden) { + var updateQueue = finishedWork.updateQueue; - if (cache !== previousCache) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; + if (updateQueue !== null) { + deferHiddenCallbacks(updateQueue); } - - popCacheProvider(workInProgress); } - if (enableTransitionTracing) { - popRootMarkerInstance(workInProgress); - } + return; + } - popRootTransition(workInProgress); - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - resetWorkInProgressVersions(); + case HostHoistable: { + { + // We cast because we always set the root at the React root and so it cannot be + // null while we are processing mutation effects + var hoistableRoot = currentHoistableRoot; + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (fiberRoot.pendingContext) { - fiberRoot.context = fiberRoot.pendingContext; - fiberRoot.pendingContext = null; - } + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } + } - if (current === null || current.child === null) { - // If we hydrated, pop so that we can delete any remaining children - // that weren't hydrated. - var wasHydrated = popHydrationState(workInProgress); + if (flags & Update) { + var currentResource = current !== null ? current.memoizedState : null; + var newResource = finishedWork.memoizedState; - if (wasHydrated) { - // If we hydrated, then we'll need to schedule an update for - // the commit side-effects on the root. - markUpdate(workInProgress); - } else { - if (current !== null) { - var prevState = current.memoizedState; + if (current === null) { + // We are mounting a new HostHoistable Fiber. We fork the mount + // behavior based on whether this instance is a Hoistable Instance + // or a Hoistable Resource + if (newResource === null) { + if (finishedWork.stateNode === null) { + finishedWork.stateNode = hydrateHoistable( + hoistableRoot, + finishedWork.type, + finishedWork.memoizedProps, + finishedWork + ); + } else { + mountHoistable( + hoistableRoot, + finishedWork.type, + finishedWork.stateNode + ); + } + } else { + finishedWork.stateNode = acquireResource( + hoistableRoot, + newResource, + finishedWork.memoizedProps + ); + } + } else if (currentResource !== newResource) { + // We are moving to or from Hoistable Resource, or between different Hoistable Resources + if (currentResource === null) { + if (current.stateNode !== null) { + unmountHoistable(current.stateNode); + } + } else { + releaseResource(currentResource); + } - if ( - // Check if this is a client root - !prevState.isDehydrated || // Check if we reverted to client rendering (e.g. due to an error) - (workInProgress.flags & ForceClientRender) !== NoFlags$1 - ) { - // Schedule an effect to clear this container at the start of the - // next commit. This handles the case of React rendering into a - // container with previous children. It's also safe to do for - // updates too, because current.child would only be null if the - // previous render was null (so the container would already - // be empty). - workInProgress.flags |= Snapshot; // If this was a forced client render, there may have been - // recoverable errors during first hydration attempt. If so, add - // them to a queue so we can log them in the commit phase. + if (newResource === null) { + mountHoistable( + hoistableRoot, + finishedWork.type, + finishedWork.stateNode + ); + } else { + acquireResource( + hoistableRoot, + newResource, + finishedWork.memoizedProps + ); + } + } else if (newResource === null && finishedWork.stateNode !== null) { + // We may have an update on a Hoistable element + var updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; - upgradeHydrationErrorsToRecoverable(); + if (updatePayload !== null) { + try { + commitUpdate( + finishedWork.stateNode, + updatePayload, + finishedWork.type, + current.memoizedProps, + finishedWork.memoizedProps, + finishedWork + ); + } catch (error) { + captureCommitPhaseError( + finishedWork, + finishedWork.return, + error + ); + } } } } - } - bubbleProperties(workInProgress); - if (enableTransitionTracing) { - if ((workInProgress.subtreeFlags & Visibility) !== NoFlags$1) { - // If any of our suspense children toggle visibility, this means that - // the pending boundaries array needs to be updated, which we only - // do in the passive phase. - workInProgress.flags |= Passive$1; - } + return; } - - return null; } + // eslint-disable-next-line-no-fallthrough - case HostHoistable: { + case HostSingleton: { { - var currentRef = current ? current.ref : null; + if (flags & Update) { + var previousWork = finishedWork.alternate; - if (currentRef !== workInProgress.ref) { - markRef(workInProgress); - } + if (previousWork === null) { + var singleton = finishedWork.stateNode; + var props = finishedWork.memoizedProps; // This was a new mount, we need to clear and set initial properties - if ( - // We are mounting and must Update this Hoistable in this commit - current === null || // We are transitioning to, from, or between Hoistable Resources - // and require an update - current.memoizedState !== workInProgress.memoizedState - ) { - markUpdate(workInProgress); - } else if (workInProgress.memoizedState === null) { - // We may have props to update on the Hoistable instance. We use the - // updateHostComponent path becuase it produces the update queue - // we need for Hoistables - updateHostComponent( - current, - workInProgress, - workInProgress.type, - workInProgress.pendingProps - ); + clearSingleton(singleton); + acquireSingletonInstance( + finishedWork.type, + props, + singleton, + finishedWork + ); + } } - - bubbleProperties(workInProgress); - return null; } } // eslint-disable-next-line-no-fallthrough - case HostSingleton: { - { - popHostContext(workInProgress); - var rootContainerInstance = getRootHostContainer(); - var type = workInProgress.type; + case HostComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (current !== null && workInProgress.stateNode != null) { - updateHostComponent(current, workInProgress, type, newProps); + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } + } - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } else { - if (!newProps) { - if (workInProgress.stateNode === null) { - throw new Error( - "We must have new props for new mounts. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } // This can happen when we abort work. + { + // TODO: ContentReset gets cleared by the children during the commit + // phase. This is a refactor hazard because it means we must read + // flags the flags after `commitReconciliationEffects` has already run; + // the order matters. We should refactor so that ContentReset does not + // rely on mutating the flag during commit. Like by setting a flag + // during the render phase instead. + if (finishedWork.flags & ContentReset) { + var instance = finishedWork.stateNode; - bubbleProperties(workInProgress); - return null; + try { + resetTextContent(instance); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } + } - var currentHostContext = getHostContext(); + if (flags & Update) { + var _instance2 = finishedWork.stateNode; - var _wasHydrated = popHydrationState(workInProgress); + if (_instance2 != 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. - if (_wasHydrated) { - // We ignore the boolean indicating there is an updateQueue because - // it is used only to set text children and HostSingletons do not - // use them. - prepareToHydrateHostInstance(workInProgress, currentHostContext); - } else { - workInProgress.stateNode = resolveSingletonInstance( - type, - newProps, - rootContainerInstance, - currentHostContext, - true - ); - markUpdate(workInProgress); - } + var oldProps = current !== null ? current.memoizedProps : newProps; + var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. - if (workInProgress.ref !== null) { - // If there is a ref on a host node we need to schedule a callback - markRef(workInProgress); + var _updatePayload = finishedWork.updateQueue; + finishedWork.updateQueue = null; + + if (_updatePayload !== null) { + try { + commitUpdate( + _instance2, + _updatePayload, + type, + oldProps, + newProps, + finishedWork + ); + } catch (error) { + captureCommitPhaseError( + finishedWork, + finishedWork.return, + error + ); + } + } } } - - bubbleProperties(workInProgress); - return null; } - } - // eslint-disable-next-line-no-fallthrough - case HostComponent: { - popHostContext(workInProgress); - var _type = workInProgress.type; + return; + } - if (current !== null && workInProgress.stateNode != null) { - updateHostComponent(current, workInProgress, _type, newProps); + case HostText: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } else { - if (!newProps) { - if (workInProgress.stateNode === null) { + if (flags & Update) { + { + if (finishedWork.stateNode === null) { throw new Error( - "We must have new props for new mounts. This error is likely " + + "This should have a text node initialized. This error is likely " + "caused by a bug in React. Please file an issue." ); - } // This can happen when we abort work. - - bubbleProperties(workInProgress); - return null; - } + } - var _currentHostContext2 = 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 whether we want to add them top->down or - // bottom->up. Top->down is faster in IE11. + 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 _wasHydrated2 = popHydrationState(workInProgress); + var oldText = current !== null ? current.memoizedProps : newText; - if (_wasHydrated2) { - // TODO: Move this and createInstance step into the beginPhase - // to consolidate. - if ( - prepareToHydrateHostInstance(workInProgress, _currentHostContext2) - ) { - // If changes to the hydrated node need to be applied at the - // commit-phase we mark this as such. - markUpdate(workInProgress); + try { + commitTextUpdate(textInstance, oldText, newText); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); } - } else { - var _rootContainerInstance = getRootHostContainer(); + } + } - var instance = createInstance( - _type, - newProps, - _rootContainerInstance, - _currentHostContext2, - workInProgress - ); - appendAllChildren(instance, workInProgress); - workInProgress.stateNode = instance; // 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. + return; + } - if (finalizeInitialChildren(instance, _type, newProps)) { - markUpdate(workInProgress); - } - } + case HostRoot: { + { + prepareToCommitHoistables(); + var previousHoistableRoot = currentHoistableRoot; + currentHoistableRoot = getHoistableRoot(root.containerInfo); + recursivelyTraverseMutationEffects(root, finishedWork); + currentHoistableRoot = previousHoistableRoot; + commitReconciliationEffects(finishedWork); + } - if (workInProgress.ref !== null) { - // If there is a ref on a host node we need to schedule a callback - markRef(workInProgress); + if (flags & Update) { + { + if (current !== null) { + var prevRootState = current.memoizedState; + + if (prevRootState.isDehydrated) { + try { + commitHydratedContainer(root.containerInfo); + } catch (error) { + captureCommitPhaseError( + finishedWork, + finishedWork.return, + error + ); + } + } + } } } - bubbleProperties(workInProgress); - return null; + return; } - 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. + case HostPortal: { + { + var _previousHoistableRoot = currentHoistableRoot; + currentHoistableRoot = getHoistableRoot( + finishedWork.stateNode.containerInfo + ); + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + currentHoistableRoot = _previousHoistableRoot; + } - updateHostText(current, workInProgress, oldText, newText); - } else { - if (typeof newText !== "string") { - if (workInProgress.stateNode === null) { - throw new Error( - "We must have new props for new mounts. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } // This can happen when we abort work. - } + return; + } - var _rootContainerInstance2 = getRootHostContainer(); + case SuspenseComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + var offscreenFiber = finishedWork.child; - var _currentHostContext3 = getHostContext(); + if (offscreenFiber.flags & Visibility) { + var newState = offscreenFiber.memoizedState; + var isHidden = newState !== null; - var _wasHydrated3 = popHydrationState(workInProgress); + if (isHidden) { + var wasHidden = + offscreenFiber.alternate !== null && + offscreenFiber.alternate.memoizedState !== null; - if (_wasHydrated3) { - if (prepareToHydrateHostTextInstance(workInProgress)) { - markUpdate(workInProgress); + if (!wasHidden) { + // TODO: Move to passive phase + markCommitTimeOfFallback(); } - } else { - workInProgress.stateNode = createTextInstance( - newText, - _rootContainerInstance2, - _currentHostContext3, - workInProgress - ); } } - bubbleProperties(workInProgress); - return null; - } + if (flags & Update) { + try { + commitSuspenseCallback(finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - case SuspenseComponent: { - popSuspenseHandler(workInProgress); - var nextState = workInProgress.memoizedState; // Special path for dehydrated boundaries. We may eventually move this - // to its own fiber type so that we can add other kinds of hydration - // boundaries that aren't associated with a Suspense tree. In anticipation - // of such a refactor, all the hydration logic is contained in - // this branch. + var wakeables = finishedWork.updateQueue; - if ( - current === null || - (current.memoizedState !== null && - current.memoizedState.dehydrated !== null) - ) { - var fallthroughToNormalSuspensePath = - completeDehydratedSuspenseBoundary( - current, - workInProgress, - nextState - ); + if (wakeables !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, wakeables); + } + } - if (!fallthroughToNormalSuspensePath) { - if (workInProgress.flags & ShouldCapture) { - // Special case. There were remaining unhydrated nodes. We treat - // this as a mismatch. Revert to client rendering. - return workInProgress; - } else { - // Did not finish hydrating, either because this is the initial - // render or because something suspended. - return null; - } - } // Continue with the normal Suspense path. + return; + } + + case OffscreenComponent: { + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(current, current.return); + } } - if ((workInProgress.flags & DidCapture) !== NoFlags$1) { - // Something suspended. Re-render with the fallback children. - workInProgress.lanes = renderLanes; // Do not reset the effect list. + var _newState = finishedWork.memoizedState; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } // Don't bubble properties in this case. + var _isHidden = _newState !== null; - return workInProgress; + var _wasHidden = current !== null && current.memoizedState !== null; + + if (finishedWork.mode & ConcurrentMode) { + // Before committing the children, track on the stack whether this + // offscreen subtree was already hidden, so that we don't unmount the + // effects again. + var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; + var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden || _isHidden; + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden || _wasHidden; + recursivelyTraverseMutationEffects(root, finishedWork); + offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; + offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; + } else { + recursivelyTraverseMutationEffects(root, finishedWork); } - var nextDidTimeout = nextState !== null; - var prevDidTimeout = current !== null && current.memoizedState !== null; + commitReconciliationEffects(finishedWork); + var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. - if (nextDidTimeout) { - var offscreenFiber = workInProgress.child; - var _previousCache = null; + offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is + // to support batching of `attach` and `detach` calls. - if ( - offscreenFiber.alternate !== null && - offscreenFiber.alternate.memoizedState !== null && - offscreenFiber.alternate.memoizedState.cachePool !== null - ) { - _previousCache = - offscreenFiber.alternate.memoizedState.cachePool.pool; + offscreenInstance._visibility &= ~OffscreenDetached; + offscreenInstance._visibility |= + offscreenInstance._pendingVisibility & OffscreenDetached; + + if (flags & Visibility) { + // Track the current state on the Offscreen instance so we can + // read it during an event + if (_isHidden) { + offscreenInstance._visibility &= ~OffscreenVisible; + } else { + offscreenInstance._visibility |= OffscreenVisible; } - var _cache = null; + if (_isHidden) { + var isUpdate = current !== null; + var wasHiddenByAncestorOffscreen = + offscreenSubtreeIsHidden || offscreenSubtreeWasHidden; // Only trigger disapper layout effects if: + // - This is an update, not first mount. + // - This Offscreen was not hidden before. + // - Ancestor Offscreen was not hidden in previous commit. - if ( - offscreenFiber.memoizedState !== null && - offscreenFiber.memoizedState.cachePool !== null - ) { - _cache = offscreenFiber.memoizedState.cachePool.pool; - } + if (isUpdate && !_wasHidden && !wasHiddenByAncestorOffscreen) { + if ((finishedWork.mode & ConcurrentMode) !== NoMode) { + // Disappear the layout effects of all the children + recursivelyTraverseDisappearLayoutEffects(finishedWork); + } + } + } // Offscreen with manual mode manages visibility manually. - if (_cache !== _previousCache) { - // Run passive effects to retain/release the cache. - offscreenFiber.flags |= Passive$1; + if (!isOffscreenManual(finishedWork)) { + // TODO: This needs to run whenever there's an insertion or update + // inside a hidden Offscreen tree. + hideOrUnhideAllChildren(finishedWork, _isHidden); } - } // If the suspended state of the boundary changes, we need to schedule - // a passive effect, which is when we process the transitions + } // TODO: Move to passive phase - if (nextDidTimeout !== prevDidTimeout) { - if (enableTransitionTracing) { - var _offscreenFiber = workInProgress.child; - _offscreenFiber.flags |= Passive$1; - } // If the suspended state of the boundary changes, we need to schedule - // an effect to toggle the subtree's visibility. When we switch from - // fallback -> primary, the inner Offscreen fiber schedules this effect - // as part of its normal complete phase. But when we switch from - // primary -> fallback, the inner Offscreen fiber does not have a complete - // phase. So we need to schedule its effect here. - // - // We also use this flag to connect/disconnect the effects, but the same - // logic applies: when re-connecting, the Offscreen fiber's complete - // phase will handle scheduling the effect. It's only when the fallback - // is active that we have to do anything special. + if (flags & Update) { + var offscreenQueue = finishedWork.updateQueue; - if (nextDidTimeout) { - var _offscreenFiber2 = workInProgress.child; - _offscreenFiber2.flags |= Visibility; + if (offscreenQueue !== null) { + var _wakeables = offscreenQueue.wakeables; + + if (_wakeables !== null) { + offscreenQueue.wakeables = null; + attachSuspenseRetryListeners(finishedWork, _wakeables); + } } } - var wakeables = workInProgress.updateQueue; + return; + } - if (wakeables !== null) { - // Schedule an effect to attach a retry listener to the promise. - // TODO: Move to passive phase - workInProgress.flags |= Update; - } + case SuspenseListComponent: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); - if ( - workInProgress.updateQueue !== null && - workInProgress.memoizedProps.suspenseCallback != null - ) { - // Always notify the callback - // TODO: Move to passive phase - workInProgress.flags |= Update; + if (flags & Update) { + var _wakeables2 = finishedWork.updateQueue; + + if (_wakeables2 !== null) { + finishedWork.updateQueue = null; + attachSuspenseRetryListeners(finishedWork, _wakeables2); + } } - bubbleProperties(workInProgress); + return; + } + case ScopeComponent: { { - if ((workInProgress.mode & ProfileMode) !== NoMode) { - if (nextDidTimeout) { - // Don't count time spent in a timed out Suspense subtree as part of the base duration. - var primaryChildFragment = workInProgress.child; + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); // TODO: This is a temporary solution that allowed us to transition away + // from React Flare on www. - if (primaryChildFragment !== null) { - // $FlowFixMe Flow doesn't support type casting in combination with the -= operator - workInProgress.treeBaseDuration -= - primaryChildFragment.treeBaseDuration; - } + if (flags & Ref) { + if (current !== null) { + safelyDetachRef(finishedWork, finishedWork.return); } + + safelyAttachRef(finishedWork, finishedWork.return); + } + + if (flags & Update) { + var scopeInstance = finishedWork.stateNode; + prepareScopeUpdate(scopeInstance, finishedWork); } } - return null; + return; } - case HostPortal: - popHostContainer(workInProgress); + default: { + recursivelyTraverseMutationEffects(root, finishedWork); + commitReconciliationEffects(finishedWork); + return; + } + } +} - if (current === null) { - preparePortalMount(workInProgress.stateNode.containerInfo); - } +function commitReconciliationEffects(finishedWork) { + // Placement effects (insertions, reorders) can be scheduled on any fiber + // type. They needs to happen after the children effects have fired, but + // before the effects on this fiber have fired. + var flags = finishedWork.flags; - bubbleProperties(workInProgress); - return null; + if (flags & Placement) { + try { + commitPlacement(finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } // 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. - case ContextProvider: - // Pop provider fiber - var context = workInProgress.type._context; - popProvider(context, workInProgress); - bubbleProperties(workInProgress); - return null; + finishedWork.flags &= ~Placement; + } - 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 (flags & Hydrating) { + finishedWork.flags &= ~Hydrating; + } +} - if (isContextProvider(_Component)) { - popContext(workInProgress); - } +function commitLayoutEffects(finishedWork, root, committedLanes) { + inProgressLanes = committedLanes; + inProgressRoot = root; + var current = finishedWork.alternate; + commitLayoutEffectOnFiber(root, current, finishedWork); + inProgressLanes = null; + inProgressRoot = null; +} - bubbleProperties(workInProgress); - return null; +function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { + var prevDebugFiber = getCurrentFiber(); + + if (parentFiber.subtreeFlags & LayoutMask) { + var child = parentFiber.child; + + while (child !== null) { + setCurrentFiber(child); + var current = child.alternate; + commitLayoutEffectOnFiber(root, current, child); + child = child.sibling; } + } - case SuspenseListComponent: { - popSuspenseListContext(workInProgress); - var renderState = workInProgress.memoizedState; + setCurrentFiber(prevDebugFiber); +} - if (renderState === null) { - // We're running in the default, "independent" mode. - // We don't do anything in this mode. - bubbleProperties(workInProgress); - return null; +function disappearLayoutEffects(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case MemoComponent: + case SimpleMemoComponent: { + // TODO (Offscreen) Check: flags & LayoutStatic + if (shouldProfile(finishedWork)) { + try { + startLayoutEffectTimer(); + commitHookEffectListUnmount( + Layout, + finishedWork, + finishedWork.return + ); + } finally { + recordLayoutEffectDuration(finishedWork); + } + } else { + commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); } - var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags$1; - var renderedTail = renderState.rendering; + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } - if (renderedTail === null) { - // We just rendered the head. - if (!didSuspendAlready) { - // This is the first pass. We need to figure out if anything is still - // suspended in the rendered set. - // If new content unsuspended, but there's still some content that - // didn't. Then we need to do a second pass that forces everything - // to keep showing their fallbacks. - // We might be suspended if something in this render pass suspended, or - // something in the previous committed pass suspended. Otherwise, - // there's no chance so we can skip the expensive call to - // findFirstSuspended. - var cannotBeSuspended = - renderHasNotSuspendedYet() && - (current === null || (current.flags & DidCapture) === NoFlags$1); + case ClassComponent: { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var instance = finishedWork.stateNode; - if (!cannotBeSuspended) { - var row = workInProgress.child; + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount( + finishedWork, + finishedWork.return, + instance + ); + } - while (row !== null) { - var suspended = findFirstSuspended(row); + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } - if (suspended !== null) { - didSuspendAlready = true; - workInProgress.flags |= DidCapture; - cutOffTailIfNeeded(renderState, false); // If this is a newly suspended tree, it might not get committed as - // part of the second pass. In that case nothing will subscribe to - // its thenables. Instead, we'll transfer its thenables to the - // SuspenseList so that it can retry if they resolve. - // There might be multiple of these in the list but since we're - // going to wait for all of them anyway, it doesn't really matter - // which ones gets to ping. In theory we could get clever and keep - // track of how many dependencies remain but it gets tricky because - // in the meantime, we can add/remove/change items and dependencies. - // We might bail out of the loop before finding any but that - // doesn't matter since that means that the other boundaries that - // we did find already has their listeners attached. + case HostHoistable: + case HostSingleton: + case HostComponent: { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } - var newThenables = suspended.updateQueue; + case OffscreenComponent: { + // TODO (Offscreen) Check: flags & RefStatic + safelyDetachRef(finishedWork, finishedWork.return); + var isHidden = finishedWork.memoizedState !== null; - if (newThenables !== null) { - workInProgress.updateQueue = newThenables; - workInProgress.flags |= Update; - } // Rerender the whole list, but this time, we'll force fallbacks - // to stay in place. - // Reset the effect flags before doing the second pass since that's now invalid. - // Reset the child fibers to their original state. + if (isHidden); + else { + recursivelyTraverseDisappearLayoutEffects(finishedWork); + } - workInProgress.subtreeFlags = NoFlags$1; - resetChildFibers(workInProgress, renderLanes); // Set up the Suspense List Context to force suspense and - // immediately rerender the children. + break; + } - pushSuspenseListContext( - workInProgress, - setShallowSuspenseListContext( - suspenseStackCursor.current, - ForceSuspenseFallback - ) - ); // Don't bubble properties in this case. + default: { + recursivelyTraverseDisappearLayoutEffects(finishedWork); + break; + } + } +} - return workInProgress.child; - } +function recursivelyTraverseDisappearLayoutEffects(parentFiber) { + // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) + var child = parentFiber.child; - row = row.sibling; - } - } + while (child !== null) { + disappearLayoutEffects(child); + child = child.sibling; + } +} - if (renderState.tail !== null && now$1() > getRenderTargetTime()) { - // We have already passed our CPU deadline but we still have rows - // left in the tail. We'll just give up further attempts to render - // the main content and only render fallbacks. - workInProgress.flags |= DidCapture; - didSuspendAlready = true; - cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this - // to get it started back up to attempt the next item. While in terms - // of priority this work has the same priority as this current render, - // it's not part of the same transition once the transition has - // committed. If it's sync, we still want to yield so that it can be - // painted. Conceptually, this is really the same as pinging. - // We can use any RetryLane even if it's the one currently rendering - // since we're leaving it behind on this node. +function reappearLayoutEffects( + finishedRoot, + current, + finishedWork, // This function visits both newly finished work and nodes that were re-used + // from a previously committed tree. We cannot check non-static flags if the + // node was reused. + includeWorkInProgressEffects +) { + // Turn on layout effects in a tree that previously disappeared. + var flags = finishedWork.flags; - workInProgress.lanes = SomeRetryLane; - } - } else { - cutOffTailIfNeeded(renderState, false); - } // Next we're going to render the tail. - } else { - // Append the rendered row to the child list. - if (!didSuspendAlready) { - var _suspended = findFirstSuspended(renderedTail); + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Check flags & LayoutStatic - if (_suspended !== null) { - workInProgress.flags |= DidCapture; - didSuspendAlready = true; // Ensure we transfer the update queue to the parent so that it doesn't - // get lost if this row ends up dropped during a second pass. + commitHookLayoutEffects(finishedWork, Layout); + break; + } - var _newThenables = _suspended.updateQueue; + case ClassComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Check for LayoutStatic flag - if (_newThenables !== null) { - workInProgress.updateQueue = _newThenables; - workInProgress.flags |= Update; - } + var instance = finishedWork.stateNode; - cutOffTailIfNeeded(renderState, true); // This might have been modified. + if (typeof instance.componentDidMount === "function") { + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } // Commit any callbacks that would have fired while the component + // was hidden. - if ( - renderState.tail === null && - renderState.tailMode === "hidden" && - !renderedTail.alternate && - !getIsHydrating() // We don't cut it if we're hydrating. - ) { - // We're done. - bubbleProperties(workInProgress); - return null; - } - } else if ( - // The time it took to render last row is greater than the remaining - // time we have to render. So rendering one more row would likely - // exceed it. - now$1() * 2 - renderState.renderingStartTime > - getRenderTargetTime() && - renderLanes !== OffscreenLane - ) { - // We have now passed our CPU deadline and we'll just give up further - // attempts to render the main content and only render fallbacks. - // The assumption is that this is usually faster. - workInProgress.flags |= DidCapture; - didSuspendAlready = true; - cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this - // to get it started back up to attempt the next item. While in terms - // of priority this work has the same priority as this current render, - // it's not part of the same transition once the transition has - // committed. If it's sync, we still want to yield so that it can be - // painted. Conceptually, this is really the same as pinging. - // We can use any RetryLane even if it's the one currently rendering - // since we're leaving it behind on this node. + var updateQueue = finishedWork.updateQueue; - workInProgress.lanes = SomeRetryLane; - } - } + if (updateQueue !== null) { + commitHiddenCallbacks(updateQueue, instance); + } // If this is newly finished work, check for setState callbacks - if (renderState.isBackwards) { - // The effect list of the backwards tail will have been added - // to the end. This breaks the guarantee that life-cycles fire in - // sibling order but that isn't a strong guarantee promised by React. - // Especially since these might also just pop in during future commits. - // Append to the beginning of the list. - renderedTail.sibling = workInProgress.child; - workInProgress.child = renderedTail; - } else { - var previousSibling = renderState.last; + if (includeWorkInProgressEffects && flags & Callback) { + commitClassCallbacks(finishedWork); + } // TODO: Check flags & RefStatic - if (previousSibling !== null) { - previousSibling.sibling = renderedTail; - } else { - workInProgress.child = renderedTail; - } + safelyAttachRef(finishedWork, finishedWork.return); + break; + } + // Unlike commitLayoutEffectsOnFiber, we don't need to handle HostRoot + // because this function only visits nodes that are inside an + // Offscreen fiber. + // case HostRoot: { + // ... + // } - renderState.last = renderedTail; - } - } + case HostHoistable: + case HostSingleton: + case HostComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // 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 (renderState.tail !== null) { - // We still have tail rows to render. - // Pop a row. - var next = renderState.tail; - renderState.rendering = next; - renderState.tail = next.sibling; - renderState.renderingStartTime = now$1(); - next.sibling = null; // Restore the context. - // TODO: We can probably just avoid popping it instead and only - // setting it the first time we go from not suspended to suspended. + if (includeWorkInProgressEffects && current === null && flags & Update) { + commitHostComponentMount(finishedWork); + } // TODO: Check flags & Ref - var suspenseContext = suspenseStackCursor.current; + safelyAttachRef(finishedWork, finishedWork.return); + break; + } - if (didSuspendAlready) { - suspenseContext = setShallowSuspenseListContext( - suspenseContext, - ForceSuspenseFallback - ); - } else { - suspenseContext = - setDefaultShallowSuspenseListContext(suspenseContext); - } + case Profiler: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Figure out how Profiler updates should work with Offscreen - pushSuspenseListContext(workInProgress, suspenseContext); // Do a pass over the next row. - // Don't bubble properties in this case. + if (includeWorkInProgressEffects && flags & Update) { + commitProfilerUpdate(finishedWork, current); + } - return next; + break; + } + + case SuspenseComponent: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); // TODO: Figure out how Suspense hydration callbacks should work + // with Offscreen. + + if (includeWorkInProgressEffects && flags & Update) { + commitSuspenseHydrationCallbacks(finishedRoot, finishedWork); } - bubbleProperties(workInProgress); - return null; + break; } - case ScopeComponent: { - { - if (current === null) { - var scopeInstance = createScopeInstance(); - workInProgress.stateNode = scopeInstance; - prepareScopeUpdate(scopeInstance, workInProgress); + case OffscreenComponent: { + var offscreenState = finishedWork.memoizedState; + var isHidden = offscreenState !== null; - if (workInProgress.ref !== null) { - markRef(workInProgress); - markUpdate(workInProgress); - } - } else { - if (workInProgress.ref !== null) { - markUpdate(workInProgress); - } + if (isHidden); + else { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); + } // TODO: Check flags & Ref - if (current.ref !== workInProgress.ref) { - markRef(workInProgress); - } - } + safelyAttachRef(finishedWork, finishedWork.return); + break; + } - bubbleProperties(workInProgress); - return null; - } + default: { + recursivelyTraverseReappearLayoutEffects( + finishedRoot, + finishedWork, + includeWorkInProgressEffects + ); + break; } + } +} - case OffscreenComponent: - case LegacyHiddenComponent: { - popSuspenseHandler(workInProgress); - popHiddenContext(workInProgress); - var _nextState = workInProgress.memoizedState; - var nextIsHidden = _nextState !== null; // Schedule a Visibility effect if the visibility has changed +function recursivelyTraverseReappearLayoutEffects( + finishedRoot, + parentFiber, + includeWorkInProgressEffects +) { + // This function visits both newly finished work and nodes that were re-used + // from a previously committed tree. We cannot check non-static flags if the + // node was reused. + var childShouldIncludeWorkInProgressEffects = + includeWorkInProgressEffects && + (parentFiber.subtreeFlags & LayoutMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - if (workInProgress.tag === LegacyHiddenComponent); - else { - if (current !== null) { - var _prevState = current.memoizedState; - var prevIsHidden = _prevState !== null; + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; - if (prevIsHidden !== nextIsHidden) { - workInProgress.flags |= Visibility; - } - } else { - // On initial mount, we only need a Visibility effect if the tree - // is hidden. - if (nextIsHidden) { - workInProgress.flags |= Visibility; - } - } - } + while (child !== null) { + var current = child.alternate; + reappearLayoutEffects( + finishedRoot, + current, + child, + childShouldIncludeWorkInProgressEffects + ); + child = child.sibling; + } + + setCurrentFiber(prevDebugFiber); +} - if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) { - bubbleProperties(workInProgress); - } else { - // Don't bubble properties for hidden children unless we're rendering - // at offscreen priority. - if ( - includesSomeLane(renderLanes, OffscreenLane) && // Also don't bubble if the tree suspended - (workInProgress.flags & DidCapture) === NoLanes - ) { - bubbleProperties(workInProgress); // Check if there was an insertion or update in the hidden subtree. - // If so, we need to hide those nodes in the commit phase, so - // schedule a visibility effect. +function commitHookPassiveMountEffects(finishedWork, hookFlags) { + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); - if ( - workInProgress.tag !== LegacyHiddenComponent && - workInProgress.subtreeFlags & (Placement | Update) - ) { - workInProgress.flags |= Visibility; - } - } - } + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } - if (workInProgress.updateQueue !== null) { - // Schedule an effect to attach Suspense retry listeners - // TODO: Move to passive phase - workInProgress.flags |= Update; - } + recordPassiveEffectDuration(finishedWork); + } else { + try { + commitHookEffectListMount(hookFlags, finishedWork); + } catch (error) { + captureCommitPhaseError(finishedWork, finishedWork.return, error); + } + } +} - { - var _previousCache2 = null; +function commitOffscreenPassiveMountEffects(current, finishedWork, instance) { + { + var previousCache = null; - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - _previousCache2 = current.memoizedState.cachePool.pool; - } + if ( + current !== null && + current.memoizedState !== null && + current.memoizedState.cachePool !== null + ) { + previousCache = current.memoizedState.cachePool.pool; + } - var _cache2 = null; + var nextCache = null; - if ( - workInProgress.memoizedState !== null && - workInProgress.memoizedState.cachePool !== null - ) { - _cache2 = workInProgress.memoizedState.cachePool.pool; - } + if ( + finishedWork.memoizedState !== null && + finishedWork.memoizedState.cachePool !== null + ) { + nextCache = finishedWork.memoizedState.cachePool.pool; + } // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). - if (_cache2 !== _previousCache2) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; - } + if (nextCache !== previousCache) { + if (nextCache != null) { + retainCache(nextCache); } - popTransition(workInProgress, current); - return null; + if (previousCache != null) { + releaseCache(previousCache); + } } + } - case CacheComponent: { - { - var _previousCache3 = null; + if (enableTransitionTracing) { + // TODO: Pre-rendering should not be counted as part of a transition. We + // may add separate logs for pre-rendering, but it's not part of the + // primary metrics. + var offscreenState = finishedWork.memoizedState; + var queue = finishedWork.updateQueue; + var isHidden = offscreenState !== null; - if (current !== null) { - _previousCache3 = current.memoizedState.cache; - } + if (queue !== null) { + if (isHidden) { + var transitions = queue.transitions; - var _cache3 = workInProgress.memoizedState.cache; + if (transitions !== null) { + transitions.forEach(function (transition) { + // Add all the transitions saved in the update queue during + // the render phase (ie the transitions associated with this boundary) + // into the transitions set. + if (instance._transitions === null) { + instance._transitions = new Set(); + } - if (_cache3 !== _previousCache3) { - // Run passive effects to retain/release the cache. - workInProgress.flags |= Passive$1; + instance._transitions.add(transition); + }); } - popCacheProvider(workInProgress); - bubbleProperties(workInProgress); - } + var markerInstances = queue.markerInstances; - return null; - } + if (markerInstances !== null) { + markerInstances.forEach(function (markerInstance) { + var markerTransitions = markerInstance.transitions; // There should only be a few tracing marker transitions because + // they should be only associated with the transition that + // caused them - case TracingMarkerComponent: { - if (enableTransitionTracing) { - var _instance3 = workInProgress.stateNode; + if (markerTransitions !== null) { + markerTransitions.forEach(function (transition) { + if (instance._transitions === null) { + instance._transitions = new Set(); + } else if (instance._transitions.has(transition)) { + if (markerInstance.pendingBoundaries === null) { + markerInstance.pendingBoundaries = new Map(); + } - if (_instance3 !== null) { - popMarkerInstance(workInProgress); - } + if (instance._pendingMarkers === null) { + instance._pendingMarkers = new Set(); + } - bubbleProperties(workInProgress); + instance._pendingMarkers.add(markerInstance); + } + }); + } + }); + } } - return null; + finishedWork.updateQueue = null; } - } - throw new Error( - "Unknown unit of work tag (" + - workInProgress.tag + - "). This error is likely caused by a bug in " + - "React. Please file an issue." - ); -} - -function unwindWork(current, workInProgress, renderLanes) { - // Note: This intentionally doesn't check if we're hydrating because comparing - // to the current tree provider fiber is just as fast and less error-prone. - // Ideally we would have a special version of the work loop only - // for hydration. - popTreeContext(workInProgress); + commitTransitionProgress(finishedWork); // TODO: Refactor this into an if/else branch - switch (workInProgress.tag) { - case ClassComponent: { - var Component = workInProgress.type; + if (!isHidden) { + instance._transitions = null; + instance._pendingMarkers = null; + } + } +} - if (isContextProvider(Component)) { - popContext(workInProgress); - } +function commitCachePassiveMountEffect(current, finishedWork) { + { + var previousCache = null; - var flags = workInProgress.flags; + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; + } - if (flags & ShouldCapture) { - workInProgress.flags = (flags & ~ShouldCapture) | DidCapture; + var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component + // could be "borrowing" a cache instance owned by some parent, + // in which case we could avoid retaining/releasing. But it + // is non-trivial to determine when that is the case, so we + // always retain/release. - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + if (nextCache !== previousCache) { + retainCache(nextCache); - return workInProgress; + if (previousCache != null) { + releaseCache(previousCache); } - - return null; } + } +} - case HostRoot: { - { - popCacheProvider(workInProgress); - } +function commitTracingMarkerPassiveMountEffect(finishedWork) { + // Get the transitions that were initiatized during the render + // and add a start transition callback for each of them + // We will only call this on initial mount of the tracing marker + // only if there are no suspense children + var instance = finishedWork.stateNode; - if (enableTransitionTracing) { - popRootMarkerInstance(workInProgress); - } + if (instance.transitions !== null && instance.pendingBoundaries === null) { + addMarkerCompleteCallbackToPendingTransition( + finishedWork.memoizedProps.name, + instance.transitions + ); + instance.transitions = null; + instance.pendingBoundaries = null; + instance.aborts = null; + instance.name = null; + } +} - popRootTransition(workInProgress); - popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); - resetWorkInProgressVersions(); - var _flags = workInProgress.flags; +function commitPassiveMountEffects( + root, + finishedWork, + committedLanes, + committedTransitions +) { + setCurrentFiber(finishedWork); + commitPassiveMountOnFiber( + root, + finishedWork, + committedLanes, + committedTransitions + ); + resetCurrentFiber(); +} - if ( - (_flags & ShouldCapture) !== NoFlags$1 && - (_flags & DidCapture) === NoFlags$1 - ) { - // There was an error during render that wasn't captured by a suspense - // boundary. Do a second pass on the root to unmount the children. - workInProgress.flags = (_flags & ~ShouldCapture) | DidCapture; - return workInProgress; - } // We unwound to the root without completing it. Exit. +function recursivelyTraversePassiveMountEffects( + root, + parentFiber, + committedLanes, + committedTransitions +) { + var prevDebugFiber = getCurrentFiber(); - return null; - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO: popHydrationState - popHostContext(workInProgress); - return null; + while (child !== null) { + setCurrentFiber(child); + commitPassiveMountOnFiber( + root, + child, + committedLanes, + committedTransitions + ); + child = child.sibling; } + } - case SuspenseComponent: { - popSuspenseHandler(workInProgress); - var suspenseState = workInProgress.memoizedState; - - if (suspenseState !== null && suspenseState.dehydrated !== null) { - if (workInProgress.alternate === null) { - throw new Error( - "Threw in newly mounted dehydrated component. This is likely a bug in " + - "React. Please file an issue." - ); - } - - resetHydrationState(); - } - - var _flags2 = workInProgress.flags; + setCurrentFiber(prevDebugFiber); +} - if (_flags2 & ShouldCapture) { - workInProgress.flags = (_flags2 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. +function commitPassiveMountOnFiber( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions +) { + // When updating this function, also update reconnectPassiveEffects, which does + // most of the same things when an offscreen tree goes from hidden -> visible, + // or when toggling effects inside a hidden tree. + var flags = finishedWork.flags; - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); - } + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); - return workInProgress; + if (flags & Passive$1) { + commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); } - return null; + break; } - case SuspenseListComponent: { - popSuspenseListContext(workInProgress); // SuspenseList doesn't actually catch anything. It should've been - // caught by a nested boundary. If not, it should bubble through. - - return null; - } + case HostRoot: { + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); - case HostPortal: - popHostContainer(workInProgress); - return null; + if (flags & Passive$1) { + { + var previousCache = null; - case ContextProvider: - var context = workInProgress.type._context; - popProvider(context, workInProgress); - return null; + if (finishedWork.alternate !== null) { + previousCache = finishedWork.alternate.memoizedState.cache; + } - case OffscreenComponent: - case LegacyHiddenComponent: { - popSuspenseHandler(workInProgress); - popHiddenContext(workInProgress); - popTransition(workInProgress, current); - var _flags3 = workInProgress.flags; + var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. + // Note that on initial mount, previousCache and nextCache will be the same + // and this retain won't occur. To counter this, we instead retain the HostRoot's + // initial cache when creating the root itself (see createFiberRoot() in + // ReactFiberRoot.js). Subsequent updates that change the cache are reflected + // here, such that previous/next caches are retained correctly. - if (_flags3 & ShouldCapture) { - workInProgress.flags = (_flags3 & ~ShouldCapture) | DidCapture; // Captured a suspense effect. Re-render the boundary. + if (nextCache !== previousCache) { + retainCache(nextCache); - if ((workInProgress.mode & ProfileMode) !== NoMode) { - transferActualDuration(workInProgress); + if (previousCache != null) { + releaseCache(previousCache); + } + } } - return workInProgress; - } + if (enableTransitionTracing) { + // Get the transitions that were initiatized during the render + // and add a start transition callback for each of them + var root = finishedWork.stateNode; + var incompleteTransitions = root.incompleteTransitions; // Initial render - return null; - } + if (committedTransitions !== null) { + committedTransitions.forEach(function (transition) { + addTransitionStartCallbackToPendingTransition(transition); + }); + clearTransitionsForLanes(finishedRoot, committedLanes); + } - case CacheComponent: - { - popCacheProvider(workInProgress); - } + incompleteTransitions.forEach(function (markerInstance, transition) { + var pendingBoundaries = markerInstance.pendingBoundaries; - return null; + if (pendingBoundaries === null || pendingBoundaries.size === 0) { + if (markerInstance.aborts === null) { + addTransitionCompleteCallbackToPendingTransition(transition); + } - case TracingMarkerComponent: - if (enableTransitionTracing) { - if (workInProgress.stateNode !== null) { - popMarkerInstance(workInProgress); + incompleteTransitions.delete(transition); + } + }); + clearTransitionsForLanes(finishedRoot, committedLanes); } } - return null; - - default: - return null; - } -} - -function unwindInterruptedWork(current, interruptedWork, renderLanes) { - // Note: This intentionally doesn't check if we're hydrating because comparing - // to the current tree provider fiber is just as fast and less error-prone. - // Ideally we would have a special version of the work loop only - // for hydration. - popTreeContext(interruptedWork); + break; + } - switch (interruptedWork.tag) { - case ClassComponent: { - var childContextTypes = interruptedWork.type.childContextTypes; + case LegacyHiddenComponent: { + { + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); - if (childContextTypes !== null && childContextTypes !== undefined) { - popContext(interruptedWork); + if (flags & Passive$1) { + var current = finishedWork.alternate; + var instance = finishedWork.stateNode; + commitOffscreenPassiveMountEffects(current, finishedWork, instance); + } } break; } - case HostRoot: { - { - popCacheProvider(interruptedWork); + case OffscreenComponent: { + // TODO: Pass `current` as argument to this function + var _instance3 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; + + if (isHidden) { + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); + } else { + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects( + finishedRoot, + finishedWork + ); + } + } else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance3._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); + } + } + } else { + // Tree is visible + if (_instance3._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); + } else { + // The effects are currently disconnected. Reconnect them, while also + // firing effects inside newly mounted trees. This also applies to + // the initial render. + _instance3._visibility |= OffscreenPassiveEffectsConnected; + var includeWorkInProgressEffects = + (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); + } } - if (enableTransitionTracing) { - popRootMarkerInstance(interruptedWork); + if (flags & Passive$1) { + var _current = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current, finishedWork, _instance3); } - popRootTransition(interruptedWork); - popHostContainer(interruptedWork); - popTopLevelContextObject(interruptedWork); - resetWorkInProgressVersions(); - break; - } - - case HostHoistable: - case HostSingleton: - case HostComponent: { - popHostContext(interruptedWork); break; } - case HostPortal: - popHostContainer(interruptedWork); - break; - - case SuspenseComponent: - popSuspenseHandler(interruptedWork); - break; - - case SuspenseListComponent: - popSuspenseListContext(interruptedWork); - break; - - case ContextProvider: - var context = interruptedWork.type._context; - popProvider(context, interruptedWork); - break; - - case OffscreenComponent: - case LegacyHiddenComponent: - popSuspenseHandler(interruptedWork); - popHiddenContext(interruptedWork); - popTransition(interruptedWork, current); - break; + case CacheComponent: { + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); - case CacheComponent: - { - popCacheProvider(interruptedWork); + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current2 = finishedWork.alternate; + commitCachePassiveMountEffect(_current2, finishedWork); } break; + } - case TracingMarkerComponent: + case TracingMarkerComponent: { if (enableTransitionTracing) { - var instance = interruptedWork.stateNode; + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); - if (instance !== null) { - popMarkerInstance(interruptedWork); + if (flags & Passive$1) { + commitTracingMarkerPassiveMountEffect(finishedWork); } - } + break; + } // Intentional fallthrough to next branch + } + // eslint-disable-next-line-no-fallthrough + + default: { + recursivelyTraversePassiveMountEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions + ); break; + } } } -var didWarnAboutUndefinedSnapshotBeforeUpdate = null; - -{ - didWarnAboutUndefinedSnapshotBeforeUpdate = new Set(); -} // Used during the commit phase to track the state of the Offscreen component stack. -// Allows us to avoid traversing the return path to find the nearest Offscreen ancestor. - -var offscreenSubtreeIsHidden = false; -var offscreenSubtreeWasHidden = false; -var PossiblyWeakSet = typeof WeakSet === "function" ? WeakSet : Set; -var nextEffect = null; // Used for Profiling builds to track updaters. - -var inProgressLanes = null; -var inProgressRoot = null; +function recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + parentFiber, + committedLanes, + committedTransitions, + includeWorkInProgressEffects +) { + // This function visits both newly finished work and nodes that were re-used + // from a previously committed tree. We cannot check non-static flags if the + // node was reused. + var childShouldIncludeWorkInProgressEffects = + includeWorkInProgressEffects && + (parentFiber.subtreeFlags & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) -function shouldProfile(current) { - return ( - (current.mode & ProfileMode) !== NoMode && - (getExecutionContext() & CommitContext) !== NoContext - ); -} + var prevDebugFiber = getCurrentFiber(); + var child = parentFiber.child; -function reportUncaughtErrorInDEV(error) { - // Wrapping each small part of the commit phase into a guarded - // callback is a bit too slow (https://github.com/facebook/react/pull/21666). - // But we rely on it to surface errors to DEV tools like overlays - // (https://github.com/facebook/react/issues/21712). - // As a compromise, rethrow only caught errors in a guard. - { - invokeGuardedCallback(null, function () { - throw error; - }); - clearCaughtError(); + while (child !== null) { + reconnectPassiveEffects( + finishedRoot, + child, + committedLanes, + committedTransitions, + childShouldIncludeWorkInProgressEffects + ); + child = child.sibling; } -} - -function callComponentWillUnmountWithTimer(current, instance) { - instance.props = current.memoizedProps; - instance.state = current.memoizedState; - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - instance.componentWillUnmount(); - } finally { - recordLayoutEffectDuration(current); - } - } else { - instance.componentWillUnmount(); - } -} // Capture errors so they don't interrupt unmounting. + setCurrentFiber(prevDebugFiber); +} -function safelyCallComponentWillUnmount( - current, - nearestMountedAncestor, - instance +function reconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, // This function visits both newly finished work and nodes that were re-used + // from a previously committed tree. We cannot check non-static flags if the + // node was reused. + includeWorkInProgressEffects ) { - try { - callComponentWillUnmountWithTimer(current, instance); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } -} // Capture errors so they don't interrupt mounting. - -function safelyAttachRef(current, nearestMountedAncestor) { - try { - commitAttachRef(current); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } -} + var flags = finishedWork.flags; -function safelyDetachRef(current, nearestMountedAncestor) { - var ref = current.ref; - var refCleanup = current.refCleanup; + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); // TODO: Check for PassiveStatic flag - if (ref !== null) { - if (typeof refCleanup === "function") { - try { - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - refCleanup(); - } finally { - recordLayoutEffectDuration(current); - } - } else { - refCleanup(); - } - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } finally { - // `refCleanup` has been called. Nullify all references to it to prevent double invocation. - current.refCleanup = null; - var finishedWork = current.alternate; + commitHookPassiveMountEffects(finishedWork, Passive); + break; + } + // Unlike commitPassiveMountOnFiber, we don't need to handle HostRoot + // because this function only visits nodes that are inside an + // Offscreen fiber. + // case HostRoot: { + // ... + // } - if (finishedWork != null) { - finishedWork.refCleanup = null; - } - } - } else if (typeof ref === "function") { - var retVal; + case LegacyHiddenComponent: { + { + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); - try { - if (shouldProfile(current)) { - try { - startLayoutEffectTimer(); - retVal = ref(null); - } finally { - recordLayoutEffectDuration(current); - } - } else { - retVal = ref(null); + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var current = finishedWork.alternate; + var instance = finishedWork.stateNode; + commitOffscreenPassiveMountEffects(current, finishedWork, instance); } - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); } - { - if (typeof retVal === "function") { - error( - "Unexpected return value from a callback ref in %s. " + - "A callback ref should not return a function.", - getComponentNameFromFiber(current) - ); - } - } - } else { - // $FlowFixMe unable to narrow type to RefObject - ref.current = null; + break; } - } -} - -function safelyCallDestroy(current, nearestMountedAncestor, destroy) { - try { - destroy(); - } catch (error) { - captureCommitPhaseError(current, nearestMountedAncestor, error); - } -} - -var focusedInstanceHandle = null; -var shouldFireAfterActiveInstanceBlur = false; -function commitBeforeMutationEffects(root, firstChild) { - focusedInstanceHandle = prepareForCommit(); - nextEffect = firstChild; - commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber - - var shouldFire = shouldFireAfterActiveInstanceBlur; - shouldFireAfterActiveInstanceBlur = false; - focusedInstanceHandle = null; - return shouldFire; -} - -function commitBeforeMutationEffects_begin() { - while (nextEffect !== null) { - var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur. - // Let's skip the whole loop if it's off. - { - // TODO: Should wrap this in flags check, too, as optimization - var deletions = fiber.deletions; + case OffscreenComponent: { + var _instance4 = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var deletion = deletions[i]; - commitBeforeMutationEffectsDeletion(deletion); + if (isHidden) { + if (_instance4._visibility & OffscreenPassiveEffectsConnected) { + // The effects are currently connected. Update them. + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); + } else { + if (finishedWork.mode & ConcurrentMode) { + // The effects are currently disconnected. Since the tree is hidden, + // don't connect them. This also applies to the initial render. + { + // "Atomic" effects are ones that need to fire on every commit, + // even during pre-rendering. An example is updating the reference + // count on cache instances. + recursivelyTraverseAtomicPassiveEffects( + finishedRoot, + finishedWork + ); + } + } else { + // Legacy Mode: Fire the effects even if the tree is hidden. + _instance4._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); + } } + } else { + // Tree is visible + // Since we're already inside a reconnecting tree, it doesn't matter + // whether the effects are currently connected. In either case, we'll + // continue traversing the tree and firing all the effects. + // + // We do need to set the "connected" flag on the instance, though. + _instance4._visibility |= OffscreenPassiveEffectsConnected; + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); } - } - - var child = fiber.child; - - if ( - (fiber.subtreeFlags & BeforeMutationMask) !== NoFlags$1 && - child !== null - ) { - child.return = fiber; - nextEffect = child; - } else { - commitBeforeMutationEffects_complete(); - } - } -} - -function commitBeforeMutationEffects_complete() { - while (nextEffect !== null) { - var fiber = nextEffect; - setCurrentFiber(fiber); - - try { - commitBeforeMutationEffectsOnFiber(fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - resetCurrentFiber(); - var sibling = fiber.sibling; + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current3 = finishedWork.alternate; + commitOffscreenPassiveMountEffects(_current3, finishedWork, _instance4); + } - if (sibling !== null) { - sibling.return = fiber.return; - nextEffect = sibling; - return; + break; } - nextEffect = fiber.return; - } -} - -function commitBeforeMutationEffectsOnFiber(finishedWork) { - var current = finishedWork.alternate; - var flags = finishedWork.flags; + case CacheComponent: { + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); - { - if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) { - // Check to see if the focused element was inside of a hidden (Suspense) subtree. - // TODO: Move this out of the hot path using a dedicated effect tag. - if ( - finishedWork.tag === SuspenseComponent && - isSuspenseBoundaryBeingHidden(current, finishedWork) && // $FlowFixMe[incompatible-call] found when upgrading Flow - doesFiberContain(finishedWork, focusedInstanceHandle) - ) { - shouldFireAfterActiveInstanceBlur = true; - beforeActiveInstanceBlur(finishedWork); + if (includeWorkInProgressEffects && flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current4 = finishedWork.alternate; + commitCachePassiveMountEffect(_current4, finishedWork); } + + break; } - } - if ((flags & Snapshot) !== NoFlags$1) { - setCurrentFiber(finishedWork); - } + case TracingMarkerComponent: { + if (enableTransitionTracing) { + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); - switch (finishedWork.tag) { - case FunctionComponent: { - { - if ((flags & Update) !== NoFlags$1) { - commitUseEffectEventMount(finishedWork); + if (includeWorkInProgressEffects && flags & Passive$1) { + commitTracingMarkerPassiveMountEffect(finishedWork); } - } - break; + break; + } // Intentional fallthrough to next branch } + // eslint-disable-next-line-no-fallthrough - case ForwardRef: - case SimpleMemoComponent: { + default: { + recursivelyTraverseReconnectPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions, + includeWorkInProgressEffects + ); break; } + } +} - case ClassComponent: { - if ((flags & Snapshot) !== NoFlags$1) { - if (current !== null) { - var prevProps = current.memoizedProps; - var prevState = current.memoizedState; - 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. - - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "getSnapshotBeforeUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } - - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "getSnapshotBeforeUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } - } - } +function recursivelyTraverseAtomicPassiveEffects( + finishedRoot, + parentFiber, + committedLanes, + committedTransitions +) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects - var snapshot = instance.getSnapshotBeforeUpdate( - finishedWork.elementType === finishedWork.type - ? prevProps - : resolveDefaultProps(finishedWork.type, prevProps), - prevState - ); + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - { - var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate; + while (child !== null) { + setCurrentFiber(child); + commitAtomicPassiveEffects(finishedRoot, child); + child = child.sibling; + } + } - if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) { - didWarnSet.add(finishedWork.type); + setCurrentFiber(prevDebugFiber); +} - error( - "%s.getSnapshotBeforeUpdate(): A snapshot value (or null) " + - "must be returned. You have returned undefined.", - getComponentNameFromFiber(finishedWork) - ); - } - } +function commitAtomicPassiveEffects( + finishedRoot, + finishedWork, + committedLanes, + committedTransitions +) { + // "Atomic" effects are ones that need to fire on every commit, even during + // pre-rendering. We call this function when traversing a hidden tree whose + // regular effects are currently disconnected. + var flags = finishedWork.flags; - instance.__reactInternalSnapshotBeforeUpdate = snapshot; - } + switch (finishedWork.tag) { + case OffscreenComponent: { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var current = finishedWork.alternate; + var instance = finishedWork.stateNode; + commitOffscreenPassiveMountEffects(current, finishedWork, instance); } break; } - case HostRoot: { - if ((flags & Snapshot) !== NoFlags$1) { - { - var root = finishedWork.stateNode; - clearContainer(root.containerInfo); - } + case CacheComponent: { + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + + if (flags & Passive$1) { + // TODO: Pass `current` as argument to this function + var _current5 = finishedWork.alternate; + commitCachePassiveMountEffect(_current5, finishedWork); } break; } - - case HostComponent: - case HostHoistable: - case HostSingleton: - case HostText: - case HostPortal: - case IncompleteClassComponent: - // Nothing to do for these component types - break; + // eslint-disable-next-line-no-fallthrough default: { - if ((flags & Snapshot) !== NoFlags$1) { - throw new Error( - "This unit of work tag should not have side-effects. This error is " + - "likely caused by a bug in React. Please file an issue." - ); - } + recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + break; } } +} - if ((flags & Snapshot) !== NoFlags$1) { - resetCurrentFiber(); - } +function commitPassiveUnmountEffects(finishedWork) { + setCurrentFiber(finishedWork); + commitPassiveUnmountOnFiber(finishedWork); + resetCurrentFiber(); } -function commitBeforeMutationEffectsDeletion(deletion) { - { - // TODO (effects) It would be nice to avoid calling doesFiberContain() - // Maybe we can repurpose one of the subtreeFlags positions for this instead? - // Use it to store which part of the tree the focused instance is in? - // This assumes we can safely determine that instance during the "render" phase. - if (doesFiberContain(deletion, focusedInstanceHandle)) { - shouldFireAfterActiveInstanceBlur = true; - beforeActiveInstanceBlur(deletion); +function detachAlternateSiblings(parentFiber) { + // A fiber was deleted from this parent fiber, but it's still part of the + // previous (alternate) parent fiber's list of children. Because children + // are a linked list, an earlier sibling that's still alive will be + // connected to the deleted fiber via its `alternate`: + // + // live fiber --alternate--> previous live fiber --sibling--> deleted + // fiber + // + // We can't disconnect `alternate` on nodes that haven't been deleted yet, + // but we can disconnect the `sibling` and `child` pointers. + var previousFiber = parentFiber.alternate; + + if (previousFiber !== null) { + var detachedChild = previousFiber.child; + + if (detachedChild !== null) { + previousFiber.child = null; + + do { + // $FlowFixMe[incompatible-use] found when upgrading Flow + var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow + + detachedChild.sibling = null; + detachedChild = detachedSibling; + } while (detachedChild !== null); } } } -function commitHookEffectListUnmount( - flags, +function commitHookPassiveUnmountEffects( finishedWork, - nearestMountedAncestor + nearestMountedAncestor, + hookFlags ) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; - - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + if (shouldProfile(finishedWork)) { + startPassiveEffectTimer(); + commitHookEffectListUnmount( + hookFlags, + finishedWork, + nearestMountedAncestor + ); + recordPassiveEffectDuration(finishedWork); + } else { + commitHookEffectListUnmount( + hookFlags, + finishedWork, + nearestMountedAncestor + ); + } +} - do { - if ((effect.tag & flags) === flags) { - // Unmount - var destroy = effect.destroy; - effect.destroy = undefined; +function recursivelyTraversePassiveUnmountEffects(parentFiber) { + // Deletions effects can be scheduled on any fiber type. They need to happen + // before the children effects have fired. + var deletions = parentFiber.deletions; - if (destroy !== undefined) { - if (enableSchedulingProfiler) { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStarted(finishedWork); - } - } + if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; // TODO: Convert this to use recursion - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + nextEffect = childToDelete; + commitPassiveUnmountEffectsInsideOfDeletedTree_begin( + childToDelete, + parentFiber + ); + } + } - safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy); + detachAlternateSiblings(parentFiber); + } - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? - if (enableSchedulingProfiler) { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectUnmountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectUnmountStopped(); - } - } - } - } + if (parentFiber.subtreeFlags & PassiveMask) { + var child = parentFiber.child; - effect = effect.next; - } while (effect !== firstEffect); + while (child !== null) { + setCurrentFiber(child); + commitPassiveUnmountOnFiber(child); + child = child.sibling; + } } + + setCurrentFiber(prevDebugFiber); } -function commitHookEffectListMount(flags, finishedWork) { - var updateQueue = finishedWork.updateQueue; - var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; +function commitPassiveUnmountOnFiber(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + recursivelyTraversePassiveUnmountEffects(finishedWork); - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + if (finishedWork.flags & Passive$1) { + commitHookPassiveUnmountEffects( + finishedWork, + finishedWork.return, + Passive | HasEffect + ); + } - do { - if ((effect.tag & flags) === flags) { - if (enableSchedulingProfiler) { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStarted(finishedWork); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStarted(finishedWork); - } - } // Mount + break; + } - var create = effect.create; + case OffscreenComponent: { + var instance = finishedWork.stateNode; + var nextState = finishedWork.memoizedState; + var isHidden = nextState !== null; - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(true); - } - } + if ( + isHidden && + instance._visibility & OffscreenPassiveEffectsConnected && // For backwards compatibility, don't unmount when a tree suspends. In + // the future we may change this to unmount after a delay. + (finishedWork.return === null || + finishedWork.return.tag !== SuspenseComponent) + ) { + // The effects are currently connected. Disconnect them. + // TODO: Add option or heuristic to delay before disconnecting the + // effects. Then if the tree reappears before the delay has elapsed, we + // can skip toggling the effects entirely. + instance._visibility &= ~OffscreenPassiveEffectsConnected; + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + } else { + recursivelyTraversePassiveUnmountEffects(finishedWork); + } - effect.destroy = create(); + break; + } - { - if ((flags & Insertion) !== NoFlags) { - setIsRunningInsertionEffect(false); - } - } + default: { + recursivelyTraversePassiveUnmountEffects(finishedWork); + break; + } + } +} - if (enableSchedulingProfiler) { - if ((flags & Passive) !== NoFlags) { - markComponentPassiveEffectMountStopped(); - } else if ((flags & Layout) !== NoFlags) { - markComponentLayoutEffectMountStopped(); - } - } +function recursivelyTraverseDisconnectPassiveEffects(parentFiber) { + // Deletions effects can be scheduled on any fiber type. They need to happen + // before the children effects have fired. + var deletions = parentFiber.deletions; - { - var destroy = effect.destroy; + if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { + if (deletions !== null) { + for (var i = 0; i < deletions.length; i++) { + var childToDelete = deletions[i]; // TODO: Convert this to use recursion - if (destroy !== undefined && typeof destroy !== "function") { - var hookName = void 0; + nextEffect = childToDelete; + commitPassiveUnmountEffectsInsideOfDeletedTree_begin( + childToDelete, + parentFiber + ); + } + } - if ((effect.tag & Layout) !== NoFlags$1) { - hookName = "useLayoutEffect"; - } else if ((effect.tag & Insertion) !== NoFlags$1) { - hookName = "useInsertionEffect"; - } else { - hookName = "useEffect"; - } + detachAlternateSiblings(parentFiber); + } - var addendum = void 0; + var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag - if (destroy === null) { - addendum = - " You returned null. If your effect does not require clean " + - "up, return undefined (or nothing)."; - } else if (typeof destroy.then === "function") { - addendum = - "\n\nIt looks like you wrote " + - hookName + - "(async () => ...) or returned a Promise. " + - "Instead, write the async function inside your effect " + - "and call it immediately:\n\n" + - hookName + - "(() => {\n" + - " async function fetchData() {\n" + - " // You can await here\n" + - " const response = await MyAPI.getData(someId);\n" + - " // ...\n" + - " }\n" + - " fetchData();\n" + - "}, [someId]); // Or [] if effect doesn't need props or state\n\n" + - "Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching"; - } else { - addendum = " You returned: " + destroy; - } + var child = parentFiber.child; - error( - "%s must not return anything besides a function, " + - "which is used for clean-up.%s", - hookName, - addendum - ); - } - } + while (child !== null) { + setCurrentFiber(child); + disconnectPassiveEffect(child); + child = child.sibling; + } + + setCurrentFiber(prevDebugFiber); +} + +function disconnectPassiveEffect(finishedWork) { + switch (finishedWork.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + // TODO: Check PassiveStatic flag + commitHookPassiveUnmountEffects( + finishedWork, + finishedWork.return, + Passive + ); // When disconnecting passive effects, we fire the effects in the same + // order as during a deletiong: parent before child + + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } + + case OffscreenComponent: { + var instance = finishedWork.stateNode; + + if (instance._visibility & OffscreenPassiveEffectsConnected) { + instance._visibility &= ~OffscreenPassiveEffectsConnected; + recursivelyTraverseDisconnectPassiveEffects(finishedWork); } - effect = effect.next; - } while (effect !== firstEffect); + break; + } + + default: { + recursivelyTraverseDisconnectPassiveEffects(finishedWork); + break; + } } } -function commitUseEffectEventMount(finishedWork) { - var updateQueue = finishedWork.updateQueue; - var eventPayloads = updateQueue !== null ? updateQueue.events : null; +function commitPassiveUnmountEffectsInsideOfDeletedTree_begin( + deletedSubtreeRoot, + nearestMountedAncestor +) { + while (nextEffect !== null) { + var fiber = nextEffect; // Deletion effects fire in parent -> child order + // TODO: Check if fiber has a PassiveStatic flag - if (eventPayloads !== null) { - for (var ii = 0; ii < eventPayloads.length; ii++) { - var _eventPayloads$ii = eventPayloads[ii], - ref = _eventPayloads$ii.ref, - nextImpl = _eventPayloads$ii.nextImpl; - ref.impl = nextImpl; + setCurrentFiber(fiber); + commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); + resetCurrentFiber(); + var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. + + if (child !== null) { + child.return = fiber; + nextEffect = child; + } else { + commitPassiveUnmountEffectsInsideOfDeletedTree_complete( + deletedSubtreeRoot + ); } } } -function commitPassiveEffectDurations(finishedRoot, finishedWork) { - if (getExecutionContext() & CommitContext) { - // Only Profilers with work in their subtree will have an Update effect scheduled. - if ((finishedWork.flags & Update) !== NoFlags$1) { - switch (finishedWork.tag) { - case Profiler: { - var passiveEffectDuration = - finishedWork.stateNode.passiveEffectDuration; - var _finishedWork$memoize = finishedWork.memoizedProps, - id = _finishedWork$memoize.id, - onPostCommit = _finishedWork$memoize.onPostCommit; // This value will still reflect the previous commit phase. - // It does not get reset until the start of the next commit phase. +function commitPassiveUnmountEffectsInsideOfDeletedTree_complete( + deletedSubtreeRoot +) { + while (nextEffect !== null) { + var fiber = nextEffect; + var sibling = fiber.sibling; + var returnFiber = fiber.return; // Recursively traverse the entire deleted tree and clean up fiber fields. + // This is more aggressive than ideal, and the long term goal is to only + // have to detach the deleted tree at the root. - var commitTime = getCommitTime(); - var phase = finishedWork.alternate === null ? "mount" : "update"; + detachFiberAfterEffects(fiber); - { - if (isCurrentUpdateNested()) { - phase = "nested-update"; - } - } + if (fiber === deletedSubtreeRoot) { + nextEffect = null; + return; + } - if (typeof onPostCommit === "function") { - onPostCommit(id, phase, passiveEffectDuration, commitTime); - } // Bubble times to the next nearest ancestor Profiler. - // After we process that Profiler, we'll bubble further up. + if (sibling !== null) { + sibling.return = returnFiber; + nextEffect = sibling; + return; + } - var parentFiber = finishedWork.return; + nextEffect = returnFiber; + } +} - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.passiveEffectDuration += passiveEffectDuration; - break outer; +function commitPassiveUnmountInsideDeletedTreeOnFiber( + current, + nearestMountedAncestor +) { + switch (current.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + commitHookPassiveUnmountEffects(current, nearestMountedAncestor, Passive); + break; + } + // TODO: run passive unmount effects when unmounting a root. + // Because passive unmount effects are not currently run, + // the cache instance owned by the root will never be freed. + // When effects are run, the cache should be freed here: + // case HostRoot: { + // if (enableCache) { + // const cache = current.memoizedState.cache; + // releaseCache(cache); + // } + // break; + // } - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.passiveEffectDuration += passiveEffectDuration; - break outer; - } + case LegacyHiddenComponent: + case OffscreenComponent: { + { + if ( + current.memoizedState !== null && + current.memoizedState.cachePool !== null + ) { + var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. + // Note that this is only reached in the non-suspended/visible case: + // when the content is suspended/hidden, the retain/release occurs + // via the parent Suspense component (see case above). - parentFiber = parentFiber.return; + if (cache != null) { + retainCache(cache); } - - break; } } - } - } -} -function commitHookLayoutEffects(finishedWork, hookFlags) { - // At this point layout effects have already been destroyed (during mutation phase). - // This is done to prevent sibling component effects from interfering with each other, - // e.g. a destroy function in one component should never override a ref set - // by a create function in another component during the same commit. - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + break; } - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } -} + case SuspenseComponent: { + if (enableTransitionTracing) { + // We need to mark this fiber's parents as deleted + var offscreenFiber = current.child; + var instance = offscreenFiber.stateNode; + var transitions = instance._transitions; -function commitClassLayoutLifecycles(finishedWork, current) { - var instance = finishedWork.stateNode; + if (transitions !== null) { + var abortReason = { + reason: "suspense", + name: current.memoizedProps.unstable_name || null + }; - if (current === null) { - // 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. - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "componentDidMount. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } + if ( + current.memoizedState === null || + current.memoizedState.dehydrated === null + ) { + abortParentMarkerTransitionsForDeletedFiber( + offscreenFiber, + abortReason, + transitions, + instance, + true + ); - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "componentDidMount. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); + if (nearestMountedAncestor !== null) { + abortParentMarkerTransitionsForDeletedFiber( + nearestMountedAncestor, + abortReason, + transitions, + instance, + false + ); + } + } } } + + break; } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + case CacheComponent: { + { + var _cache = current.memoizedState.cache; + releaseCache(_cache); } - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + break; } - } else { - var prevProps = - finishedWork.elementType === finishedWork.type - ? current.memoizedProps - : resolveDefaultProps(finishedWork.type, current.memoizedProps); - var prevState = current.memoizedState; // 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. - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "componentDidUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } + case TracingMarkerComponent: { + if (enableTransitionTracing) { + // We need to mark this fiber's parents as deleted + var _instance5 = current.stateNode; + var _transitions = _instance5.transitions; - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "componentDidUpdate. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" + if (_transitions !== null) { + var _abortReason = { + reason: "marker", + name: current.memoizedProps.name + }; + abortParentMarkerTransitionsForDeletedFiber( + current, + _abortReason, + _transitions, + null, + true ); - } - } - } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + if (nearestMountedAncestor !== null) { + abortParentMarkerTransitionsForDeletedFiber( + nearestMountedAncestor, + _abortReason, + _transitions, + null, + false + ); + } + } } - recordLayoutEffectDuration(finishedWork); - } else { - try { - instance.componentDidUpdate( - prevProps, - prevState, - instance.__reactInternalSnapshotBeforeUpdate - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + break; } } } -function commitClassCallbacks(finishedWork) { - // TODO: I think this is now always non-null by the time it reaches the - // commit phase. Consider removing the type check. - var updateQueue = finishedWork.updateQueue; +function invokeLayoutEffectMountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListMount(Layout | HasEffect, fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } - if (updateQueue !== null) { - var instance = finishedWork.stateNode; + break; + } - { - if ( - finishedWork.type === finishedWork.elementType && - !didWarnAboutReassigningProps - ) { - if (instance.props !== finishedWork.memoizedProps) { - error( - "Expected %s props to match memoized props before " + - "processing the update queue. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.props`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); - } + case ClassComponent: { + var instance = fiber.stateNode; - if (instance.state !== finishedWork.memoizedState) { - error( - "Expected %s state to match memoized state before " + - "processing the update queue. " + - "This might either be because of a bug in React, or because " + - "a component reassigns its own `this.state`. " + - "Please file an issue.", - getComponentNameFromFiber(finishedWork) || "instance" - ); + try { + instance.componentDidMount(); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } - } - } // 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. - try { - commitCallbacks(updateQueue, instance); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + break; + } } } } -function commitHostComponentMount(finishedWork) { - var type = finishedWork.type; - var props = finishedWork.memoizedProps; - var instance = finishedWork.stateNode; +function invokePassiveEffectMountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListMount(Passive | HasEffect, fiber); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); + } - try { - commitMount(instance, type, props, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + break; + } + } } } -function commitProfilerUpdate(finishedWork, current) { - if (getExecutionContext() & CommitContext) { - try { - var _finishedWork$memoize2 = finishedWork.memoizedProps, - onCommit = _finishedWork$memoize2.onCommit, - onRender = _finishedWork$memoize2.onRender; - var effectDuration = finishedWork.stateNode.effectDuration; - var commitTime = getCommitTime(); - var phase = current === null ? "mount" : "update"; - - if (enableProfilerNestedUpdatePhase) { - if (isCurrentUpdateNested()) { - phase = "nested-update"; +function invokeLayoutEffectUnmountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListUnmount(Layout | HasEffect, fiber, fiber.return); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } - } - if (typeof onRender === "function") { - onRender( - finishedWork.memoizedProps.id, - phase, - finishedWork.actualDuration, - finishedWork.treeBaseDuration, - finishedWork.actualStartTime, - commitTime - ); + break; } - if (enableProfilerCommitHooks) { - if (typeof onCommit === "function") { - onCommit( - finishedWork.memoizedProps.id, - phase, - effectDuration, - commitTime - ); - } // Schedule a passive effect for this Profiler to call onPostCommit hooks. - // This effect should be scheduled even if there is no onPostCommit callback for this Profiler, - // because the effect is also where times bubble to parent Profilers. - - enqueuePendingPassiveProfilerEffect(finishedWork); // Propagate layout effect durations to the next nearest Profiler ancestor. - // Do not reset these values until the next render so DevTools has a chance to read them first. - - var parentFiber = finishedWork.return; + case ClassComponent: { + var instance = fiber.stateNode; - outer: while (parentFiber !== null) { - switch (parentFiber.tag) { - case HostRoot: - var root = parentFiber.stateNode; - root.effectDuration += effectDuration; - break outer; + if (typeof instance.componentWillUnmount === "function") { + safelyCallComponentWillUnmount(fiber, fiber.return, instance); + } - case Profiler: - var parentStateNode = parentFiber.stateNode; - parentStateNode.effectDuration += effectDuration; - break outer; - } + break; + } + } + } +} - parentFiber = parentFiber.return; +function invokePassiveEffectUnmountInDEV(fiber) { + { + // We don't need to re-check StrictEffectsMode here. + // This function is only called if that check has already passed. + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + try { + commitHookEffectListUnmount(Passive | HasEffect, fiber, fiber.return); + } catch (error) { + captureCommitPhaseError(fiber, fiber.return, error); } } - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); } } } -function commitLayoutEffectOnFiber( - finishedRoot, - current, - finishedWork, - committedLanes -) { - // When updating this function, also update reappearLayoutEffects, which does - // most of the same things when an offscreen tree goes from hidden -> visible. - var flags = finishedWork.flags; +function getCacheSignal() { + var cache = readContext(CacheContext); + return cache.controller.signal; +} - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); +function getCacheForType(resourceType) { + var cache = readContext(CacheContext); + var cacheForType = cache.data.get(resourceType); - if (flags & Update) { - commitHookLayoutEffects(finishedWork, Layout | HasEffect); - } + if (cacheForType === undefined) { + cacheForType = resourceType(); + cache.data.set(resourceType, cacheForType); + } - break; + return cacheForType; +} + +var DefaultCacheDispatcher = { + getCacheSignal: getCacheSignal, + getCacheForType: getCacheForType +}; + +if (typeof Symbol === "function" && Symbol.for) { + var symbolFor = Symbol.for; + symbolFor("selector.component"); + symbolFor("selector.has_pseudo_class"); + symbolFor("selector.role"); + symbolFor("selector.test_id"); + symbolFor("selector.text"); +} +var commitHooks = []; +function onCommitRoot() { + { + commitHooks.forEach(function (commitHook) { + return commitHook(); + }); + } +} + +var ReactCurrentActQueue$1 = ReactSharedInternals.ReactCurrentActQueue; +function isLegacyActEnvironment(fiber) { + { + // Legacy mode. We preserve the behavior of React 17's act. It assumes an + // act environment whenever `jest` is defined, but you can still turn off + // spurious warnings by setting IS_REACT_ACT_ENVIRONMENT explicitly + // to false. + var isReactActEnvironmentGlobal = // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global + typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] + ? IS_REACT_ACT_ENVIRONMENT + : undefined; // $FlowFixMe - Flow doesn't know about jest + + var jestIsDefined = typeof jest !== "undefined"; + return jestIsDefined && isReactActEnvironmentGlobal !== false; + } +} +function isConcurrentActEnvironment() { + { + var isReactActEnvironmentGlobal = // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global + typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] + ? IS_REACT_ACT_ENVIRONMENT + : undefined; + + if ( + !isReactActEnvironmentGlobal && + ReactCurrentActQueue$1.current !== null + ) { + // TODO: Include link to relevant documentation page. + error( + "The current testing environment is not configured to support " + + "act(...)" + ); } - case ClassComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); + return isReactActEnvironmentGlobal; + } +} - if (flags & Update) { - commitClassLayoutLifecycles(finishedWork, current); - } +var postPaintCallbackScheduled = false; +var callbacks = []; +function schedulePostPaintCallback(callback) { + callbacks.push(callback); - if (flags & Callback) { - commitClassCallbacks(finishedWork); + if (!postPaintCallbackScheduled) { + postPaintCallbackScheduled = true; + requestPostPaintCallback(function (endTime) { + for (var i = 0; i < callbacks.length; i++) { + callbacks[i](endTime); } - if (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); - } + postPaintCallbackScheduled = false; + callbacks = []; + }); + } +} - break; - } +var ceil = Math.ceil; +var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; +var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, + ReactCurrentCache = ReactSharedInternals.ReactCurrentCache, + ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, + ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig, + ReactCurrentActQueue = ReactSharedInternals.ReactCurrentActQueue; +var NoContext = + /* */ + 0; +var BatchedContext = + /* */ + 1; +var RenderContext = + /* */ + 2; +var CommitContext = + /* */ + 4; +var RootInProgress = 0; +var RootFatalErrored = 1; +var RootErrored = 2; +var RootSuspended = 3; +var RootSuspendedWithDelay = 4; +var RootCompleted = 5; +var RootDidNotComplete = 6; // Describes where we are in the React execution stack - case HostRoot: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); +var executionContext = NoContext; // The root we're working on - if (flags & Callback) { - // TODO: I think this is now always non-null by the time it reaches the - // commit phase. Consider removing the type check. - var updateQueue = finishedWork.updateQueue; +var workInProgressRoot = null; // The fiber we're working on - if (updateQueue !== null) { - var instance = null; +var workInProgress = null; // The lanes we're rendering - if (finishedWork.child !== null) { - switch (finishedWork.child.tag) { - case HostSingleton: - case HostComponent: - instance = getPublicInstance(finishedWork.child.stateNode); - break; +var workInProgressRootRenderLanes = NoLanes; +var NotSuspended = 0; +var SuspendedOnError = 1; +var SuspendedOnData = 2; +var SuspendedOnImmediate = 3; +var SuspendedOnDeprecatedThrowPromise = 4; +var SuspendedAndReadyToContinue = 5; +var SuspendedOnHydration = 6; // When this is true, the work-in-progress fiber just suspended (or errored) and +// we've yet to unwind the stack. In some cases, we may yield to the main thread +// after this happens. If the fiber is pinged before we resume, we can retry +// immediately instead of unwinding the stack. - case ClassComponent: - instance = finishedWork.child.stateNode; - break; - } - } +var workInProgressSuspendedReason = NotSuspended; +var workInProgressThrownValue = null; // Whether a ping listener was attached during this render. This is slightly +// different that whether something suspended, because we don't add multiple +// listeners to a promise we've already seen (per root and lane). - try { - commitCallbacks(updateQueue, instance); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } +var workInProgressRootDidAttachPingListener = false; // A contextual version of workInProgressRootRenderLanes. It is a superset of +// the lanes that we started working on at the root. When we enter a subtree +// that is currently hidden, we add the lanes that would have committed if +// the hidden tree hadn't been deferred. This is modified by the +// HiddenContext module. +// +// Most things in the work loop should deal with workInProgressRootRenderLanes. +// Most things in begin/complete phases should deal with renderLanes. - break; - } +var renderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. - case HostHoistable: { - { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); +var workInProgressRootExitStatus = RootInProgress; // A fatal error, if one is thrown - if (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); - } +var workInProgressRootFatalError = null; // The work left over by components that were visited during this render. Only +// includes unprocessed updates, not work in bailed out children. - break; - } - } - // eslint-disable-next-line-no-fallthrough +var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. - case HostSingleton: - case HostComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // 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. +var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). - if (current === null && flags & Update) { - commitHostComponentMount(finishedWork); - } +var workInProgressRootPingedLanes = NoLanes; // Errors that are thrown during the render phase. - if (flags & Ref) { - safelyAttachRef(finishedWork, finishedWork.return); - } +var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. +// We will log them once the tree commits. - break; - } +var workInProgressRootRecoverableErrors = null; // The most recent time we committed a fallback. This lets us ensure a train +// model where we don't commit new loading states in too quick succession. - case Profiler: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); // TODO: Should this fire inside an offscreen tree? Or should it wait to - // fire when the tree becomes visible again. +var globalMostRecentFallbackTime = 0; +var FALLBACK_THROTTLE_MS = 500; // The absolute time for when we should start giving up on rendering +// more and prefer CPU suspense heuristics instead. - if (flags & Update) { - commitProfilerUpdate(finishedWork, current); - } +var workInProgressRootRenderTargetTime = Infinity; // How long a render is supposed to take before we start following CPU +// suspense heuristics and opt out of rendering more content. - break; +var RENDER_TIMEOUT_MS = 500; +var workInProgressTransitions = null; +function getWorkInProgressTransitions() { + return workInProgressTransitions; +} +var currentPendingTransitionCallbacks = null; +var currentEndTime = null; +function addTransitionStartCallbackToPendingTransition(transition) { + if (enableTransitionTracing) { + if (currentPendingTransitionCallbacks === null) { + currentPendingTransitionCallbacks = { + transitionStart: [], + transitionProgress: null, + transitionComplete: null, + markerProgress: null, + markerIncomplete: null, + markerComplete: null + }; } - case SuspenseComponent: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - - if (flags & Update) { - commitSuspenseHydrationCallbacks(finishedRoot, finishedWork); - } + if (currentPendingTransitionCallbacks.transitionStart === null) { + currentPendingTransitionCallbacks.transitionStart = []; + } - break; + currentPendingTransitionCallbacks.transitionStart.push(transition); + } +} +function addMarkerProgressCallbackToPendingTransition( + markerName, + transitions, + pendingBoundaries +) { + if (enableTransitionTracing) { + if (currentPendingTransitionCallbacks === null) { + currentPendingTransitionCallbacks = { + transitionStart: null, + transitionProgress: null, + transitionComplete: null, + markerProgress: new Map(), + markerIncomplete: null, + markerComplete: null + }; } - case OffscreenComponent: { - var isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode; + if (currentPendingTransitionCallbacks.markerProgress === null) { + currentPendingTransitionCallbacks.markerProgress = new Map(); + } - if (isModernRoot) { - var isHidden = finishedWork.memoizedState !== null; - var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden; + currentPendingTransitionCallbacks.markerProgress.set(markerName, { + pendingBoundaries: pendingBoundaries, + transitions: transitions + }); + } +} +function addMarkerIncompleteCallbackToPendingTransition( + markerName, + transitions, + aborts +) { + if (enableTransitionTracing) { + if (currentPendingTransitionCallbacks === null) { + currentPendingTransitionCallbacks = { + transitionStart: null, + transitionProgress: null, + transitionComplete: null, + markerProgress: null, + markerIncomplete: new Map(), + markerComplete: null + }; + } - if (newOffscreenSubtreeIsHidden); - else { - // The Offscreen tree is visible. - var wasHidden = current !== null && current.memoizedState !== null; - var newOffscreenSubtreeWasHidden = - wasHidden || offscreenSubtreeWasHidden; - var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; - var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden; - offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden; + if (currentPendingTransitionCallbacks.markerIncomplete === null) { + currentPendingTransitionCallbacks.markerIncomplete = new Map(); + } - if (offscreenSubtreeWasHidden && !prevOffscreenSubtreeWasHidden) { - // This is the root of a reappearing boundary. As we continue - // traversing the layout effects, we must also re-mount layout - // effects that were unmounted when the Offscreen subtree was - // hidden. So this is a superset of the normal commitLayoutEffects. - var includeWorkInProgressEffects = - (finishedWork.subtreeFlags & LayoutMask) !== NoFlags$1; - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - } else { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - } + currentPendingTransitionCallbacks.markerIncomplete.set(markerName, { + transitions: transitions, + aborts: aborts + }); + } +} +function addMarkerCompleteCallbackToPendingTransition(markerName, transitions) { + if (enableTransitionTracing) { + if (currentPendingTransitionCallbacks === null) { + currentPendingTransitionCallbacks = { + transitionStart: null, + transitionProgress: null, + transitionComplete: null, + markerProgress: null, + markerIncomplete: null, + markerComplete: new Map() + }; + } - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; - } - } else { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - } + if (currentPendingTransitionCallbacks.markerComplete === null) { + currentPendingTransitionCallbacks.markerComplete = new Map(); + } - if (flags & Ref) { - var props = finishedWork.memoizedProps; + currentPendingTransitionCallbacks.markerComplete.set( + markerName, + transitions + ); + } +} +function addTransitionProgressCallbackToPendingTransition( + transition, + boundaries +) { + if (enableTransitionTracing) { + if (currentPendingTransitionCallbacks === null) { + currentPendingTransitionCallbacks = { + transitionStart: null, + transitionProgress: new Map(), + transitionComplete: null, + markerProgress: null, + markerIncomplete: null, + markerComplete: null + }; + } - if (props.mode === "manual") { - safelyAttachRef(finishedWork, finishedWork.return); - } else { - safelyDetachRef(finishedWork, finishedWork.return); - } - } + if (currentPendingTransitionCallbacks.transitionProgress === null) { + currentPendingTransitionCallbacks.transitionProgress = new Map(); + } - break; + currentPendingTransitionCallbacks.transitionProgress.set( + transition, + boundaries + ); + } +} +function addTransitionCompleteCallbackToPendingTransition(transition) { + if (enableTransitionTracing) { + if (currentPendingTransitionCallbacks === null) { + currentPendingTransitionCallbacks = { + transitionStart: null, + transitionProgress: null, + transitionComplete: [], + markerProgress: null, + markerIncomplete: null, + markerComplete: null + }; } - default: { - recursivelyTraverseLayoutEffects(finishedRoot, finishedWork); - break; + if (currentPendingTransitionCallbacks.transitionComplete === null) { + currentPendingTransitionCallbacks.transitionComplete = []; } + + currentPendingTransitionCallbacks.transitionComplete.push(transition); } } -function abortRootTransitions( - root, - abort, - deletedTransitions, - deletedOffscreenInstance, - isInDeletedTree -) { - if (enableTransitionTracing) { - var rootTransitions = root.incompleteTransitions; - deletedTransitions.forEach(function (transition) { - if (rootTransitions.has(transition)) { - var transitionInstance = rootTransitions.get(transition); +function resetRenderTimer() { + workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; +} - if (transitionInstance.aborts === null) { - transitionInstance.aborts = []; - } +function getRenderTargetTime() { + return workInProgressRootRenderTargetTime; +} +var hasUncaughtError = false; +var firstUncaughtError = null; +var legacyErrorBoundariesThatAlreadyFailed = null; // Only used when enableProfilerNestedUpdateScheduledHook is true; +// to track which root is currently committing layout effects. - transitionInstance.aborts.push(abort); +var rootCommittingMutationOrLayoutEffects = null; +var rootDoesHavePassiveEffects = false; +var rootWithPendingPassiveEffects = null; +var pendingPassiveEffectsLanes = NoLanes; +var pendingPassiveProfilerEffects = []; +var pendingPassiveEffectsRemainingLanes = NoLanes; +var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates - if (deletedOffscreenInstance !== null) { - if ( - transitionInstance.pendingBoundaries !== null && - transitionInstance.pendingBoundaries.has(deletedOffscreenInstance) - ) { - // $FlowFixMe[incompatible-use] found when upgrading Flow - transitionInstance.pendingBoundaries.delete( - deletedOffscreenInstance - ); - } - } - } - }); - } +var NESTED_UPDATE_LIMIT = 50; +var nestedUpdateCount = 0; +var rootWithNestedUpdates = null; +var isFlushingPassiveEffects = false; +var didScheduleUpdateDuringPassiveEffects = false; +var NESTED_PASSIVE_UPDATE_LIMIT = 50; +var nestedPassiveUpdateCount = 0; +var rootWithPassiveNestedUpdates = null; // If two updates are scheduled within the same event, we should treat their +// event times as simultaneous, even if the actual clock time has advanced +// between the first and second call. + +var currentEventTime = NoTimestamp; +var currentEventTransitionLane = NoLanes; +var isRunningInsertionEffect = false; +function getWorkInProgressRoot() { + return workInProgressRoot; +} +function getWorkInProgressRootRenderLanes() { + return workInProgressRootRenderLanes; } +function requestEventTime() { + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + // We're inside React, so it's fine to read the actual time. + return now$1(); + } // We're not inside React, so we may be in the middle of a browser event. -function abortTracingMarkerTransitions( - abortedFiber, - abort, - deletedTransitions, - deletedOffscreenInstance, - isInDeletedTree -) { - if (enableTransitionTracing) { - var markerInstance = abortedFiber.stateNode; - var markerTransitions = markerInstance.transitions; - var pendingBoundaries = markerInstance.pendingBoundaries; + if (currentEventTime !== NoTimestamp) { + // Use the same start time for all updates until we enter React again. + return currentEventTime; + } // This is the first update since React yielded. Compute a new start time. - if (markerTransitions !== null) { - // TODO: Refactor this code. Is there a way to move this code to - // the deletions phase instead of calculating it here while making sure - // complete is called appropriately? - deletedTransitions.forEach(function (transition) { - // If one of the transitions on the tracing marker is a transition - // that was in an aborted subtree, we will abort that tracing marker - if ( - abortedFiber !== null && - markerTransitions.has(transition) && - (markerInstance.aborts === null || - !markerInstance.aborts.includes(abort)) - ) { - if (markerInstance.transitions !== null) { - if (markerInstance.aborts === null) { - markerInstance.aborts = [abort]; - addMarkerIncompleteCallbackToPendingTransition( - abortedFiber.memoizedProps.name, - markerInstance.transitions, - markerInstance.aborts - ); - } else { - markerInstance.aborts.push(abort); - } // We only want to call onTransitionProgress when the marker hasn't been - // deleted + currentEventTime = now$1(); + return currentEventTime; +} +function requestUpdateLane(fiber) { + // Special cases + var mode = fiber.mode; - if ( - deletedOffscreenInstance !== null && - !isInDeletedTree && - pendingBoundaries !== null && - pendingBoundaries.has(deletedOffscreenInstance) - ) { - pendingBoundaries.delete(deletedOffscreenInstance); - addMarkerProgressCallbackToPendingTransition( - abortedFiber.memoizedProps.name, - deletedTransitions, - pendingBoundaries - ); - } - } - } - }); - } + if ((mode & ConcurrentMode) === NoMode) { + return SyncLane; + } else if ( + !deferRenderPhaseUpdateToNextBatch && + (executionContext & RenderContext) !== NoContext && + workInProgressRootRenderLanes !== NoLanes + ) { + // This is a render phase update. These are not officially supported. The + // old behavior is to give this the same "thread" (lanes) as + // whatever is currently rendering. So if you call `setState` on a component + // that happens later in the same render, it will flush. Ideally, we want to + // remove the special case and treat them as if they came from an + // interleaved event. Regardless, this pattern is not officially supported. + // This behavior is only a fallback. The flag only exists until we can roll + // out the setState warning, since existing code might accidentally rely on + // the current behavior. + return pickArbitraryLane(workInProgressRootRenderLanes); } -} -function abortParentMarkerTransitionsForDeletedFiber( - abortedFiber, - abort, - deletedTransitions, - deletedOffscreenInstance, - isInDeletedTree -) { - if (enableTransitionTracing) { - // Find all pending markers that are waiting on child suspense boundaries in the - // aborted subtree and cancels them - var fiber = abortedFiber; + var isTransition = requestCurrentTransition() !== NoTransition; - while (fiber !== null) { - switch (fiber.tag) { - case TracingMarkerComponent: - abortTracingMarkerTransitions( - fiber, - abort, - deletedTransitions, - deletedOffscreenInstance, - isInDeletedTree - ); - break; + if (isTransition) { + if (ReactCurrentBatchConfig$1.transition !== null) { + var transition = ReactCurrentBatchConfig$1.transition; - case HostRoot: - var root = fiber.stateNode; - abortRootTransitions( - root, - abort, - deletedTransitions, - deletedOffscreenInstance - ); - break; + if (!transition._updatedFibers) { + transition._updatedFibers = new Set(); } - fiber = fiber.return; + transition._updatedFibers.add(fiber); + } // The algorithm for assigning an update to a lane should be stable for all + // updates at the same priority within the same event. To do this, the + // inputs to the algorithm must be the same. + // + // The trick we use is to cache the first of each of these inputs within an + // event. Then reset the cached values once we can be sure the event is + // over. Our heuristic for that is whenever we enter a concurrent work loop. + + if (currentEventTransitionLane === NoLane) { + // All transitions within the same event are assigned the same lane. + currentEventTransitionLane = claimNextTransitionLane(); } - } -} -function commitTransitionProgress(offscreenFiber) { - if (enableTransitionTracing) { - // This function adds suspense boundaries to the root - // or tracing marker's pendingBoundaries map. - // When a suspense boundary goes from a resolved to a fallback - // state we add the boundary to the map, and when it goes from - // a fallback to a resolved state, we remove the boundary from - // the map. - // We use stateNode on the Offscreen component as a stable object - // that doesnt change from render to render. This way we can - // distinguish between different Offscreen instances (vs. the same - // Offscreen instance with different fibers) - var offscreenInstance = offscreenFiber.stateNode; - var prevState = null; - var previousFiber = offscreenFiber.alternate; + return currentEventTransitionLane; + } // Updates originating inside certain React methods, like flushSync, have + // their priority set by tracking it with a context variable. + // + // The opaque type returned by the host config is internally a lane, so we can + // use that directly. + // TODO: Move this type conversion to the event priority module. - if (previousFiber !== null && previousFiber.memoizedState !== null) { - prevState = previousFiber.memoizedState; - } + var updateLane = getCurrentUpdatePriority(); - var nextState = offscreenFiber.memoizedState; - var wasHidden = prevState !== null; - var isHidden = nextState !== null; - var pendingMarkers = offscreenInstance._pendingMarkers; // If there is a name on the suspense boundary, store that in - // the pending boundaries. + if (updateLane !== NoLane) { + return updateLane; + } // This update originated outside React. Ask the host environment for an + // appropriate priority, based on the type of event. + // + // The opaque type returned by the host config is internally a lane, so we can + // use that directly. + // TODO: Move this type conversion to the event priority module. - var name = null; - var parent = offscreenFiber.return; + var eventLane = getCurrentEventPriority(); + return eventLane; +} - if ( - parent !== null && - parent.tag === SuspenseComponent && - parent.memoizedProps.unstable_name - ) { - name = parent.memoizedProps.unstable_name; - } +function requestRetryLane(fiber) { + // This is a fork of `requestUpdateLane` designed specifically for Suspense + // "retries" — a special update that attempts to flip a Suspense boundary + // from its placeholder state to its primary/resolved state. + // Special cases + var mode = fiber.mode; - if (!wasHidden && isHidden) { - // The suspense boundaries was just hidden. Add the boundary - // to the pending boundary set if it's there - if (pendingMarkers !== null) { - pendingMarkers.forEach(function (markerInstance) { - var pendingBoundaries = markerInstance.pendingBoundaries; - var transitions = markerInstance.transitions; - var markerName = markerInstance.name; + if ((mode & ConcurrentMode) === NoMode) { + return SyncLane; + } - if ( - pendingBoundaries !== null && - !pendingBoundaries.has(offscreenInstance) - ) { - pendingBoundaries.set(offscreenInstance, { - name: name - }); + return claimNextRetryLane(); +} - if (transitions !== null) { - if ( - markerInstance.tag === TransitionTracingMarker && - markerName !== null - ) { - addMarkerProgressCallbackToPendingTransition( - markerName, - transitions, - pendingBoundaries - ); - } else if (markerInstance.tag === TransitionRoot) { - transitions.forEach(function (transition) { - addTransitionProgressCallbackToPendingTransition( - transition, - pendingBoundaries - ); - }); - } - } - } - }); - } - } else if (wasHidden && !isHidden) { - // The suspense boundary went from hidden to visible. Remove - // the boundary from the pending suspense boundaries set - // if it's there - if (pendingMarkers !== null) { - pendingMarkers.forEach(function (markerInstance) { - var pendingBoundaries = markerInstance.pendingBoundaries; - var transitions = markerInstance.transitions; - var markerName = markerInstance.name; +function scheduleUpdateOnFiber(root, fiber, lane, eventTime) { + { + if (isRunningInsertionEffect) { + error("useInsertionEffect must not schedule updates."); + } + } - if ( - pendingBoundaries !== null && - pendingBoundaries.has(offscreenInstance) - ) { - pendingBoundaries.delete(offscreenInstance); + { + if (isFlushingPassiveEffects) { + didScheduleUpdateDuringPassiveEffects = true; + } + } // Check if the work loop is currently suspended and waiting for data to + // finish loading. - if (transitions !== null) { - if ( - markerInstance.tag === TransitionTracingMarker && - markerName !== null - ) { - addMarkerProgressCallbackToPendingTransition( - markerName, - transitions, - pendingBoundaries - ); // If there are no more unresolved suspense boundaries, the interaction - // is considered finished + if ( + workInProgressSuspendedReason === SuspendedOnData && + root === workInProgressRoot + ) { + // The incoming update might unblock the current render. Interrupt the + // current attempt and restart from the top. + prepareFreshStack(root, NoLanes); + markRootSuspended(root, workInProgressRootRenderLanes); + } // Mark that the root has a pending update. - if (pendingBoundaries.size === 0) { - if (markerInstance.aborts === null) { - addMarkerCompleteCallbackToPendingTransition( - markerName, - transitions - ); - } + markRootUpdated(root, lane, eventTime); - markerInstance.transitions = null; - markerInstance.pendingBoundaries = null; - markerInstance.aborts = null; - } - } else if (markerInstance.tag === TransitionRoot) { - transitions.forEach(function (transition) { - addTransitionProgressCallbackToPendingTransition( - transition, - pendingBoundaries - ); - }); - } - } - } - }); + if ( + (executionContext & RenderContext) !== NoLanes && + root === workInProgressRoot + ) { + // This update was dispatched during the render phase. This is a mistake + // if the update originates from user space (with the exception of local + // hook updates, which are handled differently and don't reach this + // function), but there are some internal React features that use this as + // an implementation detail, like selective hydration. + warnAboutRenderPhaseUpdatesInDEV(fiber); // Track lanes that were updated during the render phase + } else { + // This is a normal update, scheduled from outside the render phase. For + // example, during an input event. + { + if (isDevToolsPresent) { + addFiberToLanesMap(root, fiber, lane); } } - } -} - -function hideOrUnhideAllChildren(finishedWork, isHidden) { - // Only hide or unhide the top-most host nodes. - var hostSubtreeRoot = null; - { - // 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; + warnIfUpdatesNotWrappedWithActDEV(fiber); - while (true) { + if (enableProfilerNestedUpdateScheduledHook) { if ( - node.tag === HostComponent || - node.tag === HostHoistable || - node.tag === HostSingleton + (executionContext & CommitContext) !== NoContext && + root === rootCommittingMutationOrLayoutEffects ) { - if (hostSubtreeRoot === null) { - hostSubtreeRoot = node; + if (fiber.mode & ProfileMode) { + var current = fiber; - try { - var instance = node.stateNode; + while (current !== null) { + if (current.tag === Profiler) { + var _current$memoizedProp = current.memoizedProps, + id = _current$memoizedProp.id, + onNestedUpdateScheduled = + _current$memoizedProp.onNestedUpdateScheduled; - if (isHidden) { - hideInstance(instance); - } else { - unhideInstance(node.stateNode, node.memoizedProps); + if (typeof onNestedUpdateScheduled === "function") { + onNestedUpdateScheduled(id); + } } - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } else if (node.tag === HostText) { - if (hostSubtreeRoot === null) { - try { - var _instance = node.stateNode; - if (isHidden) { - hideTextInstance(_instance); - } else { - unhideTextInstance(_instance, node.memoizedProps); - } - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + current = current.return; } } - } else if ( - (node.tag === OffscreenComponent || - node.tag === LegacyHiddenComponent) && - node.memoizedState !== null && - node !== finishedWork - ); - 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; - } + if (enableTransitionTracing) { + var transition = ReactCurrentBatchConfig$1.transition; - if (hostSubtreeRoot === node) { - hostSubtreeRoot = null; + if (transition !== null && transition.name != null) { + if (transition.startTime === -1) { + transition.startTime = now$1(); } - node = node.return; - } - - if (hostSubtreeRoot === node) { - hostSubtreeRoot = null; + addTransitionToLanesMap(root, transition, lane); } - - node.sibling.return = node.return; - node = node.sibling; } - } -} - -function commitAttachRef(finishedWork) { - var ref = finishedWork.ref; - if (ref !== null) { - var instance = finishedWork.stateNode; - var instanceToUse; - - switch (finishedWork.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - instanceToUse = getPublicInstance(instance); - break; - - default: - instanceToUse = instance; - } // Moved outside to ensure DCE works with this flag + if (root === workInProgressRoot) { + // Received an update to a tree that's in the middle of rendering. Mark + // that there was an interleaved update work on this root. Unless the + // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render + // phase update. In that case, we don't treat render phase updates as if + // they were interleaved, for backwards compat reasons. + if ( + deferRenderPhaseUpdateToNextBatch || + (executionContext & RenderContext) === NoContext + ) { + workInProgressRootInterleavedUpdatedLanes = mergeLanes( + workInProgressRootInterleavedUpdatedLanes, + lane + ); + } - if (finishedWork.tag === ScopeComponent) { - instanceToUse = instance; + if (workInProgressRootExitStatus === RootSuspendedWithDelay) { + // The root already suspended with a delay, which means this render + // definitely won't finish. Since we have a new update, let's mark it as + // suspended now, right before marking the incoming update. This has the + // effect of interrupting the current render and switching to the update. + // TODO: Make sure this doesn't override pings that happen while we've + // already started rendering. + markRootSuspended(root, workInProgressRootRenderLanes); + } } - if (typeof ref === "function") { - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - finishedWork.refCleanup = ref(instanceToUse); - } finally { - recordLayoutEffectDuration(finishedWork); - } - } else { - finishedWork.refCleanup = ref(instanceToUse); - } - } else { - { - if (!ref.hasOwnProperty("current")) { - error( - "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or React.createRef().", - getComponentNameFromFiber(finishedWork) - ); - } - } // $FlowFixMe unable to narrow type to the non-function case + ensureRootIsScheduled(root, eventTime); - ref.current = instanceToUse; + if ( + lane === SyncLane && + executionContext === NoContext && + (fiber.mode & ConcurrentMode) === NoMode && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. + !ReactCurrentActQueue.isBatchingLegacy + ) { + // Flush the synchronous work now, unless we're already working or inside + // a batch. This is intentionally inside scheduleUpdateOnFiber instead of + // scheduleCallbackForFiber to preserve the ability to schedule a callback + // without immediately flushing it. We only do this for user-initiated + // updates, to preserve historical behavior of legacy mode. + resetRenderTimer(); + flushSyncCallbacksOnlyInLegacyMode(); } } } - -function detachFiberMutation(fiber) { - // Cut off the return pointer to disconnect it from the tree. - // This enables us to detect and warn against state updates on an unmounted component. - // It also prevents events from bubbling from within disconnected components. - // - // Ideally, we should also 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. - // - // Note that we can't clear child or sibling pointers yet. - // They're needed for passive effects and for findDOMNode. - // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects). +function scheduleInitialHydrationOnRoot(root, lane, eventTime) { + // This is a special fork of scheduleUpdateOnFiber that is only used to + // schedule the initial hydration of a root that has just been created. Most + // of the stuff in scheduleUpdateOnFiber can be skipped. // - // Don't reset the alternate yet, either. We need that so we can detach the - // alternate's fields in the passive phase. Clearing the return pointer is - // sufficient for findDOMNode semantics. - var alternate = fiber.alternate; - - if (alternate !== null) { - alternate.return = null; - } - - fiber.return = null; + // The main reason for this separate path, though, is to distinguish the + // initial children from subsequent updates. In fully client-rendered roots + // (createRoot instead of hydrateRoot), all top-level renders are modeled as + // updates, but hydration roots are special because the initial render must + // match what was rendered on the server. + var current = root.current; + current.lanes = lane; + markRootUpdated(root, lane, eventTime); + ensureRootIsScheduled(root, eventTime); } +function isUnsafeClassRenderPhaseUpdate(fiber) { + // Check if this is a render phase update. Only called by class components, + // which special (deprecated) behavior for UNSAFE_componentWillReceive props. + return ( + // TODO: Remove outdated deferRenderPhaseUpdateToNextBatch experiment. We + // decided not to enable it. + (!deferRenderPhaseUpdateToNextBatch || + (fiber.mode & ConcurrentMode) === NoMode) && + (executionContext & RenderContext) !== NoContext + ); +} // Use this function to schedule a task for a root. There's only one task per +// root; if a task was already scheduled, we'll check to make sure the priority +// of the existing task is the same as the priority of the next level that the +// root has work on. This function is called on every update, and right before +// exiting a task. -function detachFiberAfterEffects(fiber) { - var alternate = fiber.alternate; - - if (alternate !== null) { - fiber.alternate = null; - detachFiberAfterEffects(alternate); - } // Clear cyclical Fiber fields. This level alone is designed to roughly - // approximate the planned Fiber refactor. In that world, `setState` will be - // bound to a special "instance" object instead of a Fiber. The Instance - // object will not have any of these fields. It will only be connected to - // the fiber tree via a single link at the root. So if this level alone is - // sufficient to fix memory issues, that bodes well for our plans. - - fiber.child = null; - fiber.deletions = null; - fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host - // tree, which has its own pointers to children, parents, and siblings. - // The other host nodes also point back to fibers, so we should detach that - // one, too. - - if (fiber.tag === HostComponent) { - var hostInstance = fiber.stateNode; - - if (hostInstance !== null) { - detachDeletedInstance(hostInstance); - } - } - - fiber.stateNode = null; - - { - fiber._debugOwner = null; - } // Theoretically, nothing in here should be necessary, because we already - // disconnected the fiber from the tree. So even if something leaks this - // particular fiber, it won't leak anything else. - - fiber.return = null; - fiber.dependencies = null; - fiber.memoizedProps = null; - fiber.memoizedState = null; - fiber.pendingProps = null; - fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead. +function ensureRootIsScheduled(root, currentTime) { + var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as + // expired so we know to work on those next. - fiber.updateQueue = null; -} + markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. -function getHostParentFiber(fiber) { - var parent = fiber.return; + var nextLanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); - while (parent !== null) { - if (isHostParent(parent)) { - return parent; + if (nextLanes === NoLanes) { + // Special case: There's nothing to work on. + if (existingCallbackNode !== null) { + cancelCallback(existingCallbackNode); } - parent = parent.return; - } + root.callbackNode = null; + root.callbackPriority = NoLane; + return; + } // If this root is currently suspended and waiting for data to resolve, don't + // schedule a task to render it. We'll either wait for a ping, or wait to + // receive an update. - throw new Error( - "Expected to find a host parent. This error is likely caused by a bug " + - "in React. Please file an issue." - ); -} + if ( + workInProgressSuspendedReason === SuspendedOnData && + workInProgressRoot === root + ) { + root.callbackPriority = NoLane; + root.callbackNode = null; + return; + } // We use the highest priority lane to represent the priority of the callback. -function isHostParent(fiber) { - return ( - fiber.tag === HostComponent || - fiber.tag === HostRoot || - fiber.tag === HostHoistable || - fiber.tag === HostSingleton || - fiber.tag === HostPortal - ); -} + var newCallbackPriority = getHighestPriorityLane(nextLanes); // Check if there's an existing task. We may be able to reuse it. -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. - // TODO: Find a more efficient way to do this. - var node = fiber; + var existingCallbackPriority = root.callbackPriority; - 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; - } // $FlowFixMe[incompatible-type] found when upgrading Flow + if ( + existingCallbackPriority === newCallbackPriority && // Special case related to `act`. If the currently scheduled task is a + // Scheduler task, rather than an `act` task, cancel it and re-scheduled + // on the `act` queue. + !( + ReactCurrentActQueue.current !== null && + existingCallbackNode !== fakeActCallbackNode + ) + ) { + { + // If we're going to re-use an existing task, it needs to exist. + // Assume that discrete update microtasks are non-cancellable and null. + // TODO: Temporary until we confirm this warning is not fired. + if ( + existingCallbackNode == null && + !includesSyncLane(existingCallbackPriority) + ) { + error( + "Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue." + ); + } + } // The priority hasn't changed. We can reuse the existing task. Exit. - node = node.return; - } + return; + } - node.sibling.return = node.return; - node = node.sibling; + if (existingCallbackNode != null) { + // Cancel the existing callback. We'll schedule a new one below. + cancelCallback(existingCallbackNode); + } // Schedule a new callback. - while ( - node.tag !== HostComponent && - node.tag !== HostText && - node.tag !== HostSingleton && - node.tag !== DehydratedFragment - ) { - // 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.flags & 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. + var newCallbackNode; - if (node.child === null || node.tag === HostPortal) { - continue siblings; - } else { - node.child.return = node; - node = node.child; + if (includesSyncLane(newCallbackPriority)) { + // Special case: Sync React callbacks are scheduled on a special + // internal queue + if (root.tag === LegacyRoot) { + if (ReactCurrentActQueue.isBatchingLegacy !== null) { + ReactCurrentActQueue.didScheduleLegacyUpdate = true; } - } // Check if this host node is stable or about to be placed. - if (!(node.flags & Placement)) { - // Found it! - return node.stateNode; + scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root)); + } else { + scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); } - } -} -function commitPlacement(finishedWork) { - { - if (finishedWork.tag === HostSingleton) { - // Singletons are already in the Host and don't need to be placed - // Since they operate somewhat like Portals though their children will - // have Placement and will get placed inside them - return; + { + // Flush the queue in a microtask. + if (ReactCurrentActQueue.current !== null) { + // Inside `act`, use our internal `act` queue so that these get flushed + // at the end of the current scope even when using the sync version + // of `act`. + ReactCurrentActQueue.current.push(flushSyncCallbacks); + } else { + scheduleMicrotask(function () { + // In Safari, appending an iframe forces microtasks to run. + // https://github.com/facebook/react/issues/22459 + // We don't support running callbacks in the middle of render + // or commit so we need to check against that. + if ( + (executionContext & (RenderContext | CommitContext)) === + NoContext + ) { + // Note that this would still prematurely flush the callbacks + // if this happens outside render or commit phase (e.g. in an event). + flushSyncCallbacks(); + } + }); + } } - } // Recursively insert all host nodes into the parent. - var parentFiber = getHostParentFiber(finishedWork); - - switch (parentFiber.tag) { - case HostSingleton: { - { - var parent = parentFiber.stateNode; - 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. + newCallbackNode = null; + } else { + var schedulerPriorityLevel; - insertOrAppendPlacementNode(finishedWork, before, parent); + switch (lanesToEventPriority(nextLanes)) { + case DiscreteEventPriority: + schedulerPriorityLevel = ImmediatePriority; break; - } - } - // eslint-disable-next-line no-fallthrough - - case HostComponent: { - var _parent = parentFiber.stateNode; - if (parentFiber.flags & ContentReset) { - // Reset the text content of the parent before doing any insertions - resetTextContent(_parent); // Clear ContentReset from the effect tag + case ContinuousEventPriority: + schedulerPriorityLevel = UserBlockingPriority; + break; - parentFiber.flags &= ~ContentReset; - } + case DefaultEventPriority: + schedulerPriorityLevel = NormalPriority$1; + break; - 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. + case IdleEventPriority: + schedulerPriorityLevel = IdlePriority; + break; - insertOrAppendPlacementNode(finishedWork, _before, _parent); - break; + default: + schedulerPriorityLevel = NormalPriority$1; + break; } - case HostRoot: - case HostPortal: { - var _parent2 = parentFiber.stateNode.containerInfo; + newCallbackNode = scheduleCallback( + schedulerPriorityLevel, + performConcurrentWorkOnRoot.bind(null, root) + ); + } - var _before2 = getHostSibling(finishedWork); + root.callbackPriority = newCallbackPriority; + root.callbackNode = newCallbackNode; +} // This is the entry point for every concurrent task, i.e. anything that +// goes through Scheduler. - insertOrAppendPlacementNodeIntoContainer( - finishedWork, - _before2, - _parent2 - ); - break; - } - // eslint-disable-next-line-no-fallthrough +function performConcurrentWorkOnRoot(root, didTimeout) { + { + resetNestedUpdateFlag(); + } // Since we know we're in a React event, we can clear the current + // event time. The next update will compute a new event time. - default: - throw new Error( - "Invalid host parent fiber. This error is likely caused by a bug " + - "in React. Please file an issue." - ); - } -} + currentEventTime = NoTimestamp; + currentEventTransitionLane = NoLanes; -function insertOrAppendPlacementNodeIntoContainer(node, before, parent) { - var tag = node.tag; - var isHost = tag === HostComponent || tag === HostText; + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Should not already be working."); + } // Flush any pending passive effects before deciding which lanes to work on, + // in case they schedule additional work. - if (isHost) { - var stateNode = node.stateNode; + var originalCallbackNode = root.callbackNode; + var didFlushPassiveEffects = flushPassiveEffects(); - if (before) { - insertInContainerBefore(parent, stateNode, before); - } else { - appendChildToContainer(parent, stateNode); + if (didFlushPassiveEffects) { + // Something in the passive effect phase may have canceled the current task. + // Check if the task node for this root was changed. + if (root.callbackNode !== originalCallbackNode) { + // The current task was canceled. Exit. We don't need to call + // `ensureRootIsScheduled` because the check above implies either that + // there's a new task, or that there's no remaining work on this root. + return null; } - } else if (tag === HostPortal || tag === HostSingleton); - else { - var child = node.child; + } // Determine the next lanes to work on, using the fields stored + // on the root. - if (child !== null) { - insertOrAppendPlacementNodeIntoContainer(child, before, parent); - var sibling = child.sibling; + var lanes = getNextLanes( + root, + root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes + ); - while (sibling !== null) { - insertOrAppendPlacementNodeIntoContainer(sibling, before, parent); - sibling = sibling.sibling; - } - } - } -} + if (lanes === NoLanes) { + // Defensive coding. This is never expected to happen. + return null; + } // We disable time-slicing in some cases: if the work has been CPU-bound + // for too long ("expired" work, to prevent starvation), or we're in + // sync-updates-by-default mode. + // TODO: We only check `didTimeout` defensively, to account for a Scheduler + // bug we're still investigating. Once the bug in Scheduler is fixed, + // we can remove this, since we track expiration ourselves. -function insertOrAppendPlacementNode(node, before, parent) { - var tag = node.tag; - var isHost = tag === HostComponent || tag === HostText; + var shouldTimeSlice = + !includesBlockingLane(root, lanes) && + !includesExpiredLane(root, lanes) && + (disableSchedulerTimeoutInWorkLoop || !didTimeout); + var exitStatus = shouldTimeSlice + ? renderRootConcurrent(root, lanes) + : renderRootSync(root, lanes); - if (isHost) { - var stateNode = node.stateNode; + if (exitStatus !== RootInProgress) { + if (exitStatus === RootErrored) { + // If something threw an error, try rendering one more time. We'll + // render synchronously to block concurrent data mutations, and we'll + // includes all pending updates are included. If it still fails after + // the second attempt, we'll give up and commit the resulting tree. + var originallyAttemptedLanes = lanes; + var errorRetryLanes = getLanesToRetrySynchronouslyOnError( + root, + originallyAttemptedLanes + ); - if (before) { - insertBefore(parent, stateNode, before); - } else { - appendChild(parent, stateNode); + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + originallyAttemptedLanes, + errorRetryLanes + ); + } } - } else if (tag === HostPortal || tag === HostSingleton); - else { - var child = node.child; - - if (child !== null) { - insertOrAppendPlacementNode(child, before, parent); - var sibling = child.sibling; - while (sibling !== null) { - insertOrAppendPlacementNode(sibling, before, parent); - sibling = sibling.sibling; - } + if (exitStatus === RootFatalErrored) { + var fatalError = workInProgressRootFatalError; + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + throw fatalError; } - } -} // These are tracked on the stack as we recursively traverse a -// deleted subtree. -// TODO: Update these during the whole mutation phase, not just during -// a deletion. -var hostParent = null; -var hostParentIsContainer = false; + if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + markRootSuspended(root, lanes); + } else { + // The render completed. + // Check if this render may have yielded to a concurrent event, and if so, + // confirm that any newly rendered stores are consistent. + // TODO: It's possible that even a concurrent render may never have yielded + // to the main thread, if it was fast enough, or if it expired. We could + // skip the consistency check in that case, too. + var renderWasConcurrent = !includesBlockingLane(root, lanes); + var finishedWork = root.current.alternate; -function commitDeletionEffects(root, returnFiber, deletedFiber) { - { - // We only have the top Fiber that was deleted but we need to recurse down its - // children to find all the terminal nodes. - // Recursively delete all host nodes from the parent, detach refs, clean - // up mounted layout effects, and call componentWillUnmount. - // We only need to remove the topmost host child in each branch. But then we - // still need to keep traversing to unmount effects, refs, and cWU. TODO: We - // could split this into two separate traversals functions, where the second - // one doesn't include any removeChild logic. This is maybe the same - // function as "disappearLayoutEffects" (or whatever that turns into after - // the layout phase is refactored to use recursion). - // Before starting, find the nearest host parent on the stack so we know - // which instance/container to remove the children from. - // TODO: Instead of searching up the fiber return path on every deletion, we - // can track the nearest host component on the JS stack as we traverse the - // tree during the commit phase. This would make insertions faster, too. - var parent = returnFiber; + if ( + renderWasConcurrent && + !isRenderConsistentWithExternalStores(finishedWork) + ) { + // A store was mutated in an interleaved event. Render again, + // synchronously, to block further mutations. + exitStatus = renderRootSync(root, lanes); // We need to check again if something threw - findParent: while (parent !== null) { - switch (parent.tag) { - case HostSingleton: - case HostComponent: { - hostParent = parent.stateNode; - hostParentIsContainer = false; - break findParent; - } + if (exitStatus === RootErrored) { + var _originallyAttemptedLanes = lanes; - case HostRoot: { - hostParent = parent.stateNode.containerInfo; - hostParentIsContainer = true; - break findParent; - } + var _errorRetryLanes = getLanesToRetrySynchronouslyOnError( + root, + _originallyAttemptedLanes + ); - case HostPortal: { - hostParent = parent.stateNode.containerInfo; - hostParentIsContainer = true; - break findParent; + if (_errorRetryLanes !== NoLanes) { + lanes = _errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + _originallyAttemptedLanes, + _errorRetryLanes + ); // We assume the tree is now consistent because we didn't yield to any + // concurrent events. + } } - } - parent = parent.return; - } + if (exitStatus === RootFatalErrored) { + var _fatalError = workInProgressRootFatalError; + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + throw _fatalError; + } // FIXME: Need to check for RootDidNotComplete again. The factoring here + // isn't ideal. + } // We now have a consistent tree. The next step is either to commit it, + // or, if something suspended, wait to commit it after a timeout. - if (hostParent === null) { - throw new Error( - "Expected to find a host parent. This error is likely caused by " + - "a bug in React. Please file an issue." - ); + root.finishedWork = finishedWork; + root.finishedLanes = lanes; + finishConcurrentRender(root, exitStatus, lanes); } - - commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber); - hostParent = null; - hostParentIsContainer = false; } - detachFiberMutation(deletedFiber); -} - -function recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - parent -) { - // TODO: Use a static flag to skip trees that don't have unmount effects - var child = parent.child; + ensureRootIsScheduled(root, now$1()); - while (child !== null) { - commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child); - child = child.sibling; + if (root.callbackNode === originalCallbackNode) { + // The task node scheduled for this root is the same one that's + // currently executed. Need to return a continuation. + return performConcurrentWorkOnRoot.bind(null, root); } + + return null; } -function commitDeletionEffectsOnFiber( - finishedRoot, - nearestMountedAncestor, - deletedFiber +function recoverFromConcurrentError( + root, + originallyAttemptedLanes, + errorRetryLanes ) { - onCommitUnmount(deletedFiber); // The cases in this outer switch modify the stack before they traverse - // into their subtree. There are simpler cases in the inner switch - // that don't modify the stack. - - switch (deletedFiber.tag) { - case HostHoistable: { - { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } - - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - - if (deletedFiber.memoizedState) { - releaseResource(deletedFiber.memoizedState); - } else if (deletedFiber.stateNode) { - unmountHoistable(deletedFiber.stateNode); - } - - return; - } - } - // eslint-disable-next-line no-fallthrough - - case HostSingleton: { - { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } - - var prevHostParent = hostParent; - var prevHostParentIsContainer = hostParentIsContainer; - hostParent = deletedFiber.stateNode; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); // Normally this is called in passive unmount effect phase however with - // HostSingleton we warn if you acquire one that is already associated to - // a different fiber. To increase our chances of avoiding this, specifically - // if you keyed a HostSingleton so there will be a delete followed by a Placement - // we treat detach eagerly here + // If an error occurred during hydration, discard server response and fall + // back to client side render. + // Before rendering again, save the errors from the previous attempt. + var errorsFromFirstAttempt = workInProgressRootConcurrentErrors; + var wasRootDehydrated = isRootDehydrated(root); - releaseSingletonInstance(deletedFiber.stateNode); - hostParent = prevHostParent; - hostParentIsContainer = prevHostParentIsContainer; - return; - } - } - // eslint-disable-next-line no-fallthrough + if (wasRootDehydrated) { + // The shell failed to hydrate. Set a flag to force a client rendering + // during the next attempt. To do this, we call prepareFreshStack now + // to create the root work-in-progress fiber. This is a bit weird in terms + // of factoring, because it relies on renderRootSync not calling + // prepareFreshStack again in the call below, which happens because the + // root and lanes haven't changed. + // + // TODO: I think what we should do is set ForceClientRender inside + // throwException, like we do for nested Suspense boundaries. The reason + // it's here instead is so we can switch to the synchronous work loop, too. + // Something to consider for a future refactor. + var rootWorkInProgress = prepareFreshStack(root, errorRetryLanes); + rootWorkInProgress.flags |= ForceClientRender; - case HostComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } // Intentional fallthrough to next branch + { + errorHydratingContainer(root.containerInfo); } - // eslint-disable-next-line-no-fallthrough + } - case HostText: { - // We only need to remove the nearest host child. Set the host parent - // to `null` on the stack to indicate that nested children don't - // need to be removed. - { - var _prevHostParent = hostParent; - var _prevHostParentIsContainer = hostParentIsContainer; - hostParent = null; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - hostParent = _prevHostParent; - hostParentIsContainer = _prevHostParentIsContainer; + var exitStatus = renderRootSync(root, errorRetryLanes); - if (hostParent !== null) { - // Now that all the child effects have unmounted, we can remove the - // node from the tree. - if (hostParentIsContainer) { - removeChildFromContainer(hostParent, deletedFiber.stateNode); - } else { - removeChild(hostParent, deletedFiber.stateNode); - } - } - } + if (exitStatus !== RootErrored) { + // Successfully finished rendering on retry + if (workInProgressRootDidAttachPingListener && !wasRootDehydrated) { + // During the synchronous render, we attached additional ping listeners. + // This is highly suggestive of an uncached promise (though it's not the + // only reason this would happen). If it was an uncached promise, then + // it may have masked a downstream error from ocurring without actually + // fixing it. Example: + // + // use(Promise.resolve('uncached')) + // throw new Error('Oops!') + // + // When this happens, there's a conflict between blocking potential + // concurrent data races and unwrapping uncached promise values. We + // have to choose one or the other. Because the data race recovery is + // a last ditch effort, we'll disable it. + root.errorRecoveryDisabledLanes = mergeLanes( + root.errorRecoveryDisabledLanes, + originallyAttemptedLanes + ); // Mark the current render as suspended and force it to restart. Once + // these lanes finish successfully, we'll re-enable the error recovery + // mechanism for subsequent updates. - return; - } + workInProgressRootInterleavedUpdatedLanes |= originallyAttemptedLanes; + return RootSuspendedWithDelay; + } // The errors from the failed first attempt have been recovered. Add + // them to the collection of recoverable errors. We'll log them in the + // commit phase. - case DehydratedFragment: { - { - var hydrationCallbacks = finishedRoot.hydrationCallbacks; + var errorsFromSecondAttempt = workInProgressRootRecoverableErrors; + workInProgressRootRecoverableErrors = errorsFromFirstAttempt; // The errors from the second attempt should be queued after the errors + // from the first attempt, to preserve the causal sequence. - if (hydrationCallbacks !== null) { - var onDeleted = hydrationCallbacks.onDeleted; + if (errorsFromSecondAttempt !== null) { + queueRecoverableErrors(errorsFromSecondAttempt); + } + } - if (onDeleted) { - onDeleted(deletedFiber.stateNode); - } - } - } // Dehydrated fragments don't have any children - // Delete the dehydrated suspense boundary and all of its content. + return exitStatus; +} - { - if (hostParent !== null) { - if (hostParentIsContainer) { - clearSuspenseBoundaryFromContainer( - hostParent, - deletedFiber.stateNode - ); - } else { - clearSuspenseBoundary(hostParent, deletedFiber.stateNode); - } - } - } +function queueRecoverableErrors(errors) { + if (workInProgressRootRecoverableErrors === null) { + workInProgressRootRecoverableErrors = errors; + } else { + // $FlowFixMe[method-unbinding] + workInProgressRootRecoverableErrors.push.apply( + workInProgressRootRecoverableErrors, + errors + ); + } +} - return; +function finishConcurrentRender(root, exitStatus, lanes) { + switch (exitStatus) { + case RootInProgress: + case RootFatalErrored: { + throw new Error("Root did not complete. This is a bug in React."); } + // Flow knows about invariant, so it complains if I add a break + // statement, but eslint doesn't know about invariant, so it complains + // if I do. eslint-disable-next-line no-fallthrough - case HostPortal: { - { - // When we go into a portal, it becomes the parent to remove from. - var _prevHostParent2 = hostParent; - var _prevHostParentIsContainer2 = hostParentIsContainer; - hostParent = deletedFiber.stateNode.containerInfo; - hostParentIsContainer = true; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - hostParent = _prevHostParent2; - hostParentIsContainer = _prevHostParentIsContainer2; - } - - return; + case RootErrored: { + // We should have already attempted to retry this tree. If we reached + // this point, it errored again. Commit it. + commitRoot( + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ); + break; } - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - if (!offscreenSubtreeWasHidden) { - var updateQueue = deletedFiber.updateQueue; + case RootSuspended: { + markRootSuspended(root, lanes); // We have an acceptable loading state. We need to figure out if we + // should immediately commit it or wait a bit. - if (updateQueue !== null) { - var lastEffect = updateQueue.lastEffect; + if ( + includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope + !shouldForceFlushFallbacksInDEV() + ) { + // This render only included retries, no updates. Throttle committing + // retries so that we don't show too many loading states too quickly. + var msUntilTimeout = + globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now$1(); // Don't bother with a very short suspense time. - if (lastEffect !== null) { - var firstEffect = lastEffect.next; - var effect = firstEffect; + if (msUntilTimeout > 10) { + var nextLanes = getNextLanes(root, NoLanes); - do { - var _effect = effect, - destroy = _effect.destroy, - tag = _effect.tag; + if (nextLanes !== NoLanes) { + // There's additional work on this root. + break; + } // The render is suspended, it hasn't timed out, and there's no + // lower priority work to do. Instead of committing the fallback + // immediately, wait for more data to arrive. - if (destroy !== undefined) { - if ((tag & Insertion) !== NoFlags) { - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } else if ((tag & Layout) !== NoFlags) { - if (enableSchedulingProfiler) { - markComponentLayoutEffectUnmountStarted(deletedFiber); - } + root.timeoutHandle = scheduleTimeout( + commitRoot.bind( + null, + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ), + msUntilTimeout + ); + break; + } + } // The work expired. Commit immediately. - if (shouldProfile(deletedFiber)) { - startLayoutEffectTimer(); - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - recordLayoutEffectDuration(deletedFiber); - } else { - safelyCallDestroy( - deletedFiber, - nearestMountedAncestor, - destroy - ); - } + commitRoot( + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ); + break; + } - if (enableSchedulingProfiler) { - markComponentLayoutEffectUnmountStopped(); - } - } - } + case RootSuspendedWithDelay: { + markRootSuspended(root, lanes); - effect = effect.next; - } while (effect !== firstEffect); - } - } + if (includesOnlyTransitions(lanes)) { + // This is a transition, so we should exit without committing a + // placeholder and without scheduling a timeout. Delay indefinitely + // until we receive more data. + break; } - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; - } + if (!shouldForceFlushFallbacksInDEV()) { + // This is not a transition, but we did trigger an avoided state. + // Schedule a placeholder to display after a short delay, using the Just + // Noticeable Difference. + // TODO: Is the JND optimization worth the added complexity? If this is + // the only reason we track the event time, then probably not. + // Consider removing. + var mostRecentEventTime = getMostRecentEventTime(root, lanes); + var eventTimeMs = mostRecentEventTime; + var timeElapsedMs = now$1() - eventTimeMs; - case ClassComponent: { - if (!offscreenSubtreeWasHidden) { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - var instance = deletedFiber.stateNode; + var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time. - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - deletedFiber, - nearestMountedAncestor, - instance + if (_msUntilTimeout > 10) { + // Instead of committing the fallback immediately, wait for more data + // to arrive. + root.timeoutHandle = scheduleTimeout( + commitRoot.bind( + null, + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ), + _msUntilTimeout ); + break; } - } + } // Commit the placeholder. - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber + commitRoot( + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions ); - return; + break; } - case ScopeComponent: { - { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - } - - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber + case RootCompleted: { + // The work completed. Ready to commit. + commitRoot( + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions ); - return; - } - - case OffscreenComponent: { - safelyDetachRef(deletedFiber, nearestMountedAncestor); - - if (deletedFiber.mode & ConcurrentMode) { - // If this offscreen component is hidden, we already unmounted it. Before - // deleting the children, track that it's already unmounted so that we - // don't attempt to unmount the effects again. - // TODO: If the tree is hidden, in most cases we should be able to skip - // over the nested children entirely. An exception is we haven't yet found - // the topmost host node to delete, which we already track on the stack. - // But the other case is portals, which need to be detached no matter how - // deeply they are nested. We should use a subtree flag to track whether a - // subtree includes a nested portal. - var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; - offscreenSubtreeWasHidden = - prevOffscreenSubtreeWasHidden || deletedFiber.memoizedState !== null; - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; - } else { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - } - break; } default: { - recursivelyTraverseDeletionEffects( - finishedRoot, - nearestMountedAncestor, - deletedFiber - ); - return; + throw new Error("Unknown root exit status."); } } } -function commitSuspenseCallback(finishedWork) { - // TODO: Move this to passive phase - var newState = finishedWork.memoizedState; +function isRenderConsistentWithExternalStores(finishedWork) { + // Search the rendered tree for external store reads, and check whether the + // stores were mutated in a concurrent event. Intentionally using an iterative + // loop instead of recursion so we can exit early. + var node = finishedWork; - if (newState !== null) { - var suspenseCallback = finishedWork.memoizedProps.suspenseCallback; + while (true) { + if (node.flags & StoreConsistency) { + var updateQueue = node.updateQueue; - if (typeof suspenseCallback === "function") { - var wakeables = finishedWork.updateQueue; + if (updateQueue !== null) { + var checks = updateQueue.stores; - if (wakeables !== null) { - suspenseCallback(new Set(wakeables)); - } - } else { - if (suspenseCallback !== undefined) { - error("Unexpected type for suspenseCallback."); + if (checks !== null) { + for (var i = 0; i < checks.length; i++) { + var check = checks[i]; + var getSnapshot = check.getSnapshot; + var renderedValue = check.value; + + try { + if (!objectIs(getSnapshot(), renderedValue)) { + // Found an inconsistent store. + return false; + } + } catch (error) { + // If `getSnapshot` throws, return `false`. This will schedule + // a re-render, and the error will be rethrown during render. + return false; + } + } + } } } - } -} -function commitSuspenseHydrationCallbacks(finishedRoot, finishedWork) { - var newState = finishedWork.memoizedState; - - if (newState === null) { - var current = finishedWork.alternate; + var child = node.child; - if (current !== null) { - var prevState = current.memoizedState; + if (node.subtreeFlags & StoreConsistency && child !== null) { + child.return = node; + node = child; + continue; + } - if (prevState !== null) { - var suspenseInstance = prevState.dehydrated; + if (node === finishedWork) { + return true; + } - if (suspenseInstance !== null) { - try { - commitHydratedSuspenseInstance(suspenseInstance); + while (node.sibling === null) { + if (node.return === null || node.return === finishedWork) { + return true; + } - if (enableSuspenseCallback) { - var hydrationCallbacks = finishedRoot.hydrationCallbacks; + node = node.return; + } - if (hydrationCallbacks !== null) { - var onHydrated = hydrationCallbacks.onHydrated; + node.sibling.return = node.return; + node = node.sibling; + } // Flow doesn't know this is unreachable, but eslint does + // eslint-disable-next-line no-unreachable - if (onHydrated) { - onHydrated(suspenseInstance); - } - } - } - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } - } - } + return true; } -function getRetryCache(finishedWork) { - // TODO: Unify the interface for the retry cache so we don't have to switch - // on the tag like this. - switch (finishedWork.tag) { - case SuspenseComponent: - case SuspenseListComponent: { - var retryCache = finishedWork.stateNode; +function markRootSuspended(root, suspendedLanes) { + // When suspending, we should always exclude lanes that were pinged or (more + // rarely, since we try to avoid it) updated during the render phase. + // TODO: Lol maybe there's a better way to factor this besides this + // obnoxiously named function :) + suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes); + suspendedLanes = removeLanes( + suspendedLanes, + workInProgressRootInterleavedUpdatedLanes + ); + markRootSuspended$1(root, suspendedLanes); +} // This is the entry point for synchronous tasks that don't go +// through Scheduler - if (retryCache === null) { - retryCache = finishedWork.stateNode = new PossiblyWeakSet(); - } +function performSyncWorkOnRoot(root) { + { + syncNestedUpdateFlag(); + } - return retryCache; - } + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Should not already be working."); + } - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var _retryCache = instance._retryCache; + flushPassiveEffects(); + var lanes = getNextLanes(root, NoLanes); - if (_retryCache === null) { - _retryCache = instance._retryCache = new PossiblyWeakSet(); - } + if (!includesSyncLane(lanes)) { + // There's no remaining sync work left. + ensureRootIsScheduled(root, now$1()); + return null; + } - return _retryCache; - } + var exitStatus = renderRootSync(root, lanes); - default: { - throw new Error( - "Unexpected Suspense handler tag (" + - finishedWork.tag + - "). This is a " + - "bug in React." + if (root.tag !== LegacyRoot && exitStatus === RootErrored) { + // If something threw an error, try rendering one more time. We'll render + // synchronously to block concurrent data mutations, and we'll includes + // all pending updates are included. If it still fails after the second + // attempt, we'll give up and commit the resulting tree. + var originallyAttemptedLanes = lanes; + var errorRetryLanes = getLanesToRetrySynchronouslyOnError( + root, + originallyAttemptedLanes + ); + + if (errorRetryLanes !== NoLanes) { + lanes = errorRetryLanes; + exitStatus = recoverFromConcurrentError( + root, + originallyAttemptedLanes, + errorRetryLanes ); } } + + if (exitStatus === RootFatalErrored) { + var fatalError = workInProgressRootFatalError; + prepareFreshStack(root, NoLanes); + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + throw fatalError; + } + + if (exitStatus === RootDidNotComplete) { + // The render unwound without completing the tree. This happens in special + // cases where need to exit the current render without producing a + // consistent tree or committing. + markRootSuspended(root, lanes); + ensureRootIsScheduled(root, now$1()); + return null; + } // We now have a consistent tree. Because this is a sync render, we + // will commit it even if something suspended. + + var finishedWork = root.current.alternate; + root.finishedWork = finishedWork; + root.finishedLanes = lanes; + commitRoot( + root, + workInProgressRootRecoverableErrors, + workInProgressTransitions + ); // Before exiting, make sure there's a callback scheduled for the next + // pending level. + + ensureRootIsScheduled(root, now$1()); + return null; } -function detachOffscreenInstance(instance) { - var fiber = instance._current; +function flushRoot(root, lanes) { + if (lanes !== NoLanes) { + markRootEntangled(root, mergeLanes(lanes, SyncLane)); + ensureRootIsScheduled(root, now$1()); - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); + if ((executionContext & (RenderContext | CommitContext)) === NoContext) { + resetRenderTimer(); + flushSyncCallbacks(); + } } +} +function getExecutionContext() { + return executionContext; +} +function batchedUpdates$1(fn, a) { + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; - if ((instance._pendingVisibility & OffscreenDetached) !== NoFlags$1) { - // The instance is already detached, this is a noop. - return; - } // TODO: There is an opportunity to optimise this by not entering commit phase - // and unmounting effects directly. - - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + try { + return fn(a); + } finally { + executionContext = prevExecutionContext; // If there were legacy sync updates, flush them at the end of the outer + // most batchedUpdates-like method. - if (root !== null) { - instance._pendingVisibility |= OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + if ( + executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. + !ReactCurrentActQueue.isBatchingLegacy + ) { + resetRenderTimer(); + flushSyncCallbacksOnlyInLegacyMode(); + } } } -function attachOffscreenInstance(instance) { - var fiber = instance._current; +// Warning, this opts-out of checking the function body. +// eslint-disable-next-line no-unused-vars +// eslint-disable-next-line no-redeclare +// eslint-disable-next-line no-redeclare - if (fiber === null) { - throw new Error( - "Calling Offscreen.detach before instance handle has been set." - ); +function flushSync$1(fn) { + // In legacy mode, we flush pending passive effects at the beginning of the + // next event, not at the end of the previous one. + if ( + rootWithPendingPassiveEffects !== null && + rootWithPendingPassiveEffects.tag === LegacyRoot && + (executionContext & (RenderContext | CommitContext)) === NoContext + ) { + flushPassiveEffects(); } - if ((instance._pendingVisibility & OffscreenDetached) === NoFlags$1) { - // The instance is already attached, this is a noop. - return; - } + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; + var prevTransition = ReactCurrentBatchConfig$1.transition; + var previousPriority = getCurrentUpdatePriority(); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + try { + ReactCurrentBatchConfig$1.transition = null; + setCurrentUpdatePriority(DiscreteEventPriority); - if (root !== null) { - instance._pendingVisibility &= ~OffscreenDetached; - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + if (fn) { + return fn(); + } else { + return undefined; + } + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig$1.transition = prevTransition; + executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch. + // Note that this will happen even if batchedUpdates is higher up + // the stack. + + if ((executionContext & (RenderContext | CommitContext)) === NoContext) { + flushSyncCallbacks(); + } } } +function isAlreadyRendering() { + // Used by the renderer to print a warning if certain APIs are called from + // the wrong context. + return (executionContext & (RenderContext | CommitContext)) !== NoContext; +} +function isInvalidExecutionContextForEventFunction() { + // Used to throw if certain APIs are called from the wrong context. + return (executionContext & RenderContext) !== NoContext; +} +function flushControlled(fn) { + var prevExecutionContext = executionContext; + executionContext |= BatchedContext; + var prevTransition = ReactCurrentBatchConfig$1.transition; + var previousPriority = getCurrentUpdatePriority(); -function attachSuspenseRetryListeners(finishedWork, wakeables) { - // If this boundary just timed out, then it will have a set of wakeables. - // For each wakeable, attach a listener so that when it resolves, React - // attempts to re-render the boundary in the primary (pre-timeout) state. - var retryCache = getRetryCache(finishedWork); - wakeables.forEach(function (wakeable) { - // Memoize using the boundary fiber to prevent redundant listeners. - var retry = resolveRetryWakeable.bind(null, finishedWork, wakeable); + try { + ReactCurrentBatchConfig$1.transition = null; + setCurrentUpdatePriority(DiscreteEventPriority); + fn(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig$1.transition = prevTransition; + executionContext = prevExecutionContext; - if (!retryCache.has(wakeable)) { - retryCache.add(wakeable); + if (executionContext === NoContext) { + // Flush the immediate callbacks that were scheduled during this batch + resetRenderTimer(); + flushSyncCallbacks(); + } + } +} // This is called by the HiddenContext module when we enter or leave a +// hidden subtree. The stack logic is managed there because that's the only +// place that ever modifies it. Which module it lives in doesn't matter for +// performance because this function will get inlined regardless - { - if (isDevToolsPresent) { - if (inProgressLanes !== null && inProgressRoot !== null) { - // If we have pending work still, associate the original updaters with it. - restorePendingUpdaters(inProgressRoot, inProgressLanes); - } else { - throw Error( - "Expected finished root and lanes to be set. This is a bug in React." - ); - } - } - } +function setRenderLanes(subtreeRenderLanes) { + renderLanes = subtreeRenderLanes; +} +function getRenderLanes() { + return renderLanes; +} - wakeable.then(retry, retry); - } - }); -} // This function detects when a Suspense boundary goes from visible to hidden. -// It returns false if the boundary is already hidden. -// TODO: Use an effect tag. +function resetWorkInProgressStack() { + if (workInProgress === null) return; + var interruptedWork; -function isSuspenseBoundaryBeingHidden(current, finishedWork) { - if (current !== null) { - var oldState = current.memoizedState; + if (workInProgressSuspendedReason === NotSuspended) { + // Normal case. Work-in-progress hasn't started yet. Unwind all + // its parents. + interruptedWork = workInProgress.return; + } else { + // Work-in-progress is in suspended state. Reset the work loop and unwind + // both the suspended fiber and all its parents. + resetSuspendedWorkLoopOnUnwind(); + interruptedWork = workInProgress; + } - if (oldState === null || oldState.dehydrated !== null) { - var newState = finishedWork.memoizedState; - return newState !== null && newState.dehydrated === null; - } + while (interruptedWork !== null) { + var current = interruptedWork.alternate; + unwindInterruptedWork(current, interruptedWork); + interruptedWork = interruptedWork.return; } - return false; -} -function commitMutationEffects(root, finishedWork, committedLanes) { - inProgressLanes = committedLanes; - inProgressRoot = root; - setCurrentFiber(finishedWork); - commitMutationEffectsOnFiber(finishedWork, root); - setCurrentFiber(finishedWork); - inProgressLanes = null; - inProgressRoot = null; + workInProgress = null; } -function recursivelyTraverseMutationEffects(root, parentFiber, lanes) { - // Deletions effects can be scheduled on any fiber type. They need to happen - // before the children effects hae fired. - var deletions = parentFiber.deletions; +function prepareFreshStack(root, lanes) { + root.finishedWork = null; + root.finishedLanes = NoLanes; + var timeoutHandle = root.timeoutHandle; - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; + if (timeoutHandle !== noTimeout) { + // The root previous suspended and scheduled a timeout to commit a fallback + // state. Now that we have additional work, cancel the timeout. + root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above - try { - commitDeletionEffects(root, parentFiber, childToDelete); - } catch (error) { - captureCommitPhaseError(childToDelete, parentFiber, error); - } - } + cancelTimeout(timeoutHandle); } - var prevDebugFiber = getCurrentFiber(); - - if (parentFiber.subtreeFlags & MutationMask) { - var child = parentFiber.child; + resetWorkInProgressStack(); + workInProgressRoot = root; + var rootWorkInProgress = createWorkInProgress(root.current, null); + workInProgress = rootWorkInProgress; + workInProgressRootRenderLanes = renderLanes = lanes; + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + workInProgressRootDidAttachPingListener = false; + workInProgressRootExitStatus = RootInProgress; + workInProgressRootFatalError = null; + workInProgressRootSkippedLanes = NoLanes; + workInProgressRootInterleavedUpdatedLanes = NoLanes; + workInProgressRootPingedLanes = NoLanes; + workInProgressRootConcurrentErrors = null; + workInProgressRootRecoverableErrors = null; + finishQueueingConcurrentUpdates(); - while (child !== null) { - setCurrentFiber(child); - commitMutationEffectsOnFiber(child, root); - child = child.sibling; - } + { + ReactStrictModeWarnings.discardPendingWarnings(); } - setCurrentFiber(prevDebugFiber); + return rootWorkInProgress; } -var currentHoistableRoot = null; - -function commitMutationEffectsOnFiber(finishedWork, root, lanes) { - var current = finishedWork.alternate; - var flags = finishedWork.flags; // The effect flag should be checked *after* we refine the type of fiber, - // because the fiber tag is more specific. An exception is any flag related - // to reconciliation, because those can be set on all fiber types. +function resetSuspendedWorkLoopOnUnwind() { + // Reset module-level state that was set during the render phase. + resetContextDependencies(); + resetHooksOnUnwind(); + resetChildReconcilerOnUnwind(); +} - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); +function handleThrow(root, thrownValue) { + // A component threw an exception. Usually this is because it suspended, but + // it also includes regular program errors. + // + // We're either going to unwind the stack to show a Suspense or error + // boundary, or we're going to replay the component again. Like after a + // promise resolves. + // + // Until we decide whether we're going to unwind or replay, we should preserve + // the current state of the work loop without resetting anything. + // + // If we do decide to unwind the stack, module-level variables will be reset + // in resetSuspendedWorkLoopOnUnwind. + // These should be reset immediately because they're only supposed to be set + // when React is executing user code. + resetHooksAfterThrow(); + resetCurrentFiber(); + ReactCurrentOwner$1.current = null; - if (flags & Update) { - try { - commitHookEffectListUnmount( - Insertion | HasEffect, - finishedWork, - finishedWork.return - ); - commitHookEffectListMount(Insertion | HasEffect, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } // Layout effects are destroyed during the mutation phase so that all - // destroy functions for all fibers are called before any create functions. - // This prevents sibling component effects from interfering with each other, - // e.g. a destroy function in one component should never override a ref set - // by a create function in another component during the same commit. + if (thrownValue === SuspenseException) { + // This is a special type of exception used for Suspense. For historical + // reasons, the rest of the Suspense implementation expects the thrown value + // to be a thenable, because before `use` existed that was the (unstable) + // API for suspending. This implementation detail can change later, once we + // deprecate the old API in favor of `use`. + thrownValue = getSuspendedThenable(); + workInProgressSuspendedReason = shouldAttemptToSuspendUntilDataResolves() + ? SuspendedOnData + : SuspendedOnImmediate; + } else if (thrownValue === SelectiveHydrationException) { + // An update flowed into a dehydrated boundary. Before we can apply the + // update, we need to finish hydrating. Interrupt the work-in-progress + // render so we can restart at the hydration lane. + // + // The ideal implementation would be able to switch contexts without + // unwinding the current stack. + // + // We could name this something more general but as of now it's the only + // case where we think this should happen. + workInProgressSuspendedReason = SuspendedOnHydration; + } else { + // This is a regular error. + var isWakeable = + thrownValue !== null && + typeof thrownValue === "object" && + typeof thrownValue.then === "function"; + workInProgressSuspendedReason = isWakeable // A wakeable object was thrown by a legacy Suspense implementation. + ? // This has slightly different behavior than suspending with `use`. + SuspendedOnDeprecatedThrowPromise // This is a regular error. If something earlier in the component already + : // suspended, we must clear the thenable state to unblock the work loop. + SuspendedOnError; + } - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + workInProgressThrownValue = thrownValue; + var erroredWork = workInProgress; - recordLayoutEffectDuration(finishedWork); - } else { - try { - commitHookEffectListUnmount( - Layout | HasEffect, - finishedWork, - finishedWork.return - ); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } - } + if (erroredWork === null) { + // This is a fatal error + workInProgressRootExitStatus = RootFatalErrored; + workInProgressRootFatalError = thrownValue; + return; + } - return; - } + if (erroredWork.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(erroredWork, true); + } - case ClassComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + if (enableSchedulingProfiler) { + markComponentRenderStopped(); - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } + switch (workInProgressSuspendedReason) { + case SuspendedOnError: { + markComponentErrored( + erroredWork, + thrownValue, + workInProgressRootRenderLanes + ); + break; } - if (flags & Callback && offscreenSubtreeIsHidden) { - var updateQueue = finishedWork.updateQueue; - - if (updateQueue !== null) { - deferHiddenCallbacks(updateQueue); - } + case SuspendedOnData: + case SuspendedOnImmediate: + case SuspendedOnDeprecatedThrowPromise: + case SuspendedAndReadyToContinue: { + var wakeable = thrownValue; + markComponentSuspended( + erroredWork, + wakeable, + workInProgressRootRenderLanes + ); + break; } - - return; } + } +} - case HostHoistable: { - { - // We cast because we always set the root at the React root and so it cannot be - // null while we are processing mutation effects - var hoistableRoot = currentHoistableRoot; - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } +function shouldAttemptToSuspendUntilDataResolves() { + // Check if there are other pending updates that might possibly unblock this + // component from suspending. This mirrors the check in + // renderDidSuspendDelayIfPossible. We should attempt to unify them somehow. + // TODO: Consider unwinding immediately, using the + // SuspendedOnHydration mechanism. + if ( + includesNonIdleWork(workInProgressRootSkippedLanes) || + includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes) + ) { + // Suspend normally. renderDidSuspendDelayIfPossible will handle + // interrupting the work loop. + return false; + } // TODO: We should be able to remove the equivalent check in + // finishConcurrentRender, and rely just on this one. - if (flags & Update) { - var currentResource = current !== null ? current.memoizedState : null; - var newResource = finishedWork.memoizedState; + if (includesOnlyTransitions(workInProgressRootRenderLanes)) { + // If we're rendering inside the "shell" of the app, it's better to suspend + // rendering and wait for the data to resolve. Otherwise, we should switch + // to a fallback and continue rendering. + return getShellBoundary() === null; + } - if (current === null) { - // We are mounting a new HostHoistable Fiber. We fork the mount - // behavior based on whether this instance is a Hoistable Instance - // or a Hoistable Resource - if (newResource === null) { - if (finishedWork.stateNode === null) { - finishedWork.stateNode = hydrateHoistable( - hoistableRoot, - finishedWork.type, - finishedWork.memoizedProps, - finishedWork - ); - } else { - mountHoistable( - hoistableRoot, - finishedWork.type, - finishedWork.stateNode - ); - } - } else { - finishedWork.stateNode = acquireResource( - hoistableRoot, - newResource, - finishedWork.memoizedProps - ); - } - } else if (currentResource !== newResource) { - // We are moving to or from Hoistable Resource, or between different Hoistable Resources - if (currentResource === null) { - if (current.stateNode !== null) { - unmountHoistable(current.stateNode); - } - } else { - releaseResource(currentResource); - } + var handler = getSuspenseHandler(); - if (newResource === null) { - mountHoistable( - hoistableRoot, - finishedWork.type, - finishedWork.stateNode - ); - } else { - acquireResource( - hoistableRoot, - newResource, - finishedWork.memoizedProps - ); - } - } else if (newResource === null && finishedWork.stateNode !== null) { - // We may have an update on a Hoistable element - var updatePayload = finishedWork.updateQueue; - finishedWork.updateQueue = null; + if (handler === null); + else { + if (includesOnlyRetries(workInProgressRootRenderLanes)) { + // During a retry, we can suspend rendering if the nearest Suspense boundary + // is the boundary of the "shell", because we're guaranteed not to block + // any new content from appearing. + return handler === getShellBoundary(); + } + } // For all other Lanes besides Transitions and Retries, we should not wait + // for the data to load. + // TODO: We should wait during Offscreen prerendering, too. - if (updatePayload !== null) { - try { - commitUpdate( - finishedWork.stateNode, - updatePayload, - finishedWork.type, - current.memoizedProps, - finishedWork.memoizedProps, - finishedWork - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } - } + return false; +} - return; - } - } - // eslint-disable-next-line-no-fallthrough +function pushDispatcher(container) { + prepareRendererToRender(container); + var prevDispatcher = ReactCurrentDispatcher.current; + ReactCurrentDispatcher.current = ContextOnlyDispatcher; - case HostSingleton: { - { - if (flags & Update) { - var previousWork = finishedWork.alternate; + if (prevDispatcher === null) { + // The React isomorphic package does not include a default dispatcher. + // Instead the first renderer will lazily attach one, in order to give + // nicer error messages. + return ContextOnlyDispatcher; + } else { + return prevDispatcher; + } +} - if (previousWork === null) { - var singleton = finishedWork.stateNode; - var props = finishedWork.memoizedProps; // This was a new mount, we need to clear and set initial properties +function popDispatcher(prevDispatcher) { + resetRendererAfterRender(); + ReactCurrentDispatcher.current = prevDispatcher; +} - clearSingleton(singleton); - acquireSingletonInstance( - finishedWork.type, - props, - singleton, - finishedWork - ); - } - } - } - } - // eslint-disable-next-line-no-fallthrough +function pushCacheDispatcher() { + { + var prevCacheDispatcher = ReactCurrentCache.current; + ReactCurrentCache.current = DefaultCacheDispatcher; + return prevCacheDispatcher; + } +} - case HostComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); +function popCacheDispatcher(prevCacheDispatcher) { + { + ReactCurrentCache.current = prevCacheDispatcher; + } +} - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } +function markCommitTimeOfFallback() { + globalMostRecentFallbackTime = now$1(); +} +function markSkippedUpdateLanes(lane) { + workInProgressRootSkippedLanes = mergeLanes( + lane, + workInProgressRootSkippedLanes + ); +} +function renderDidSuspend() { + if (workInProgressRootExitStatus === RootInProgress) { + workInProgressRootExitStatus = RootSuspended; + } +} +function renderDidSuspendDelayIfPossible() { + workInProgressRootExitStatus = RootSuspendedWithDelay; // Check if there are updates that we skipped tree that might have unblocked + // this render. - { - // TODO: ContentReset gets cleared by the children during the commit - // phase. This is a refactor hazard because it means we must read - // flags the flags after `commitReconciliationEffects` has already run; - // the order matters. We should refactor so that ContentReset does not - // rely on mutating the flag during commit. Like by setting a flag - // during the render phase instead. - if (finishedWork.flags & ContentReset) { - var instance = finishedWork.stateNode; + if ( + workInProgressRoot !== null && + (includesNonIdleWork(workInProgressRootSkippedLanes) || + includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) + ) { + // Mark the current render as suspended so that we switch to working on + // the updates that were skipped. Usually we only suspend at the end of + // the render phase. + // TODO: We should probably always mark the root as suspended immediately + // (inside this function), since by suspending at the end of the render + // phase introduces a potential mistake where we suspend lanes that were + // pinged or updated while we were rendering. + // TODO: Consider unwinding immediately, using the + // SuspendedOnHydration mechanism. + // $FlowFixMe[incompatible-call] need null check workInProgressRoot + markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes); + } +} +function renderDidError(error) { + if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { + workInProgressRootExitStatus = RootErrored; + } - try { - resetTextContent(instance); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } + if (workInProgressRootConcurrentErrors === null) { + workInProgressRootConcurrentErrors = [error]; + } else { + workInProgressRootConcurrentErrors.push(error); + } +} // Called during render to determine if anything has suspended. +// Returns false if we're not sure. - if (flags & Update) { - var _instance2 = finishedWork.stateNode; +function renderHasNotSuspendedYet() { + // If something errored or completed, we can't really be sure, + // so those are false. + return workInProgressRootExitStatus === RootInProgress; +} // TODO: Over time, this function and renderRootConcurrent have become more +// and more similar. Not sure it makes sense to maintain forked paths. Consider +// unifying them again. - if (_instance2 != 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. +function renderRootSync(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(root.containerInfo); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. - var oldProps = current !== null ? current.memoizedProps : newProps; - var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components. + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + { + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; - var _updatePayload = finishedWork.updateQueue; - finishedWork.updateQueue = null; + if (memoizedUpdaters.size > 0) { + restorePendingUpdaters(root, workInProgressRootRenderLanes); + memoizedUpdaters.clear(); + } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. + // If we bailout on this work, we'll move them back (like above). + // It's important to move them now in case the work spawns more work at the same priority with different updaters. + // That way we can keep the current update and future updates separate. - if (_updatePayload !== null) { - try { - commitUpdate( - _instance2, - _updatePayload, - type, - oldProps, - newProps, - finishedWork - ); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } - } + movePendingFibersToMemoized(root, lanes); } - - return; } - case HostText: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); + workInProgressTransitions = getTransitionsForLanes(root, lanes); + prepareFreshStack(root, lanes); + } - if (flags & Update) { - { - if (finishedWork.stateNode === null) { - throw new Error( - "This should have a text node initialized. This error is likely " + - "caused by a bug in React. Please file an issue." - ); - } + { + if (enableDebugTracing) { + logRenderStarted(lanes); + } + } - 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. + if (enableSchedulingProfiler) { + markRenderStarted(lanes); + } - var oldText = current !== null ? current.memoizedProps : newText; + outer: do { + try { + if ( + workInProgressSuspendedReason !== NotSuspended && + workInProgress !== null + ) { + // The work loop is suspended. During a synchronous render, we don't + // yield to the main thread. Immediately unwind the stack. This will + // trigger either a fallback or an error boundary. + // TODO: For discrete and "default" updates (anything that's not + // flushSync), we want to wait for the microtasks the flush before + // unwinding. Will probably implement this using renderRootConcurrent, + // or merge renderRootSync and renderRootConcurrent into the same + // function and fork the behavior some other way. + var unitOfWork = workInProgress; + var thrownValue = workInProgressThrownValue; - try { - commitTextUpdate(textInstance, oldText, newText); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); + switch (workInProgressSuspendedReason) { + case SuspendedOnHydration: { + // Selective hydration. An update flowed into a dehydrated tree. + // Interrupt the current render so the work loop can switch to the + // hydration lane. + resetWorkInProgressStack(); + workInProgressRootExitStatus = RootDidNotComplete; + break outer; + } + + default: { + // Continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + unwindSuspendedUnitOfWork(unitOfWork, thrownValue); + break; } } } - return; + workLoopSync(); + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); } + } while (true); - case HostRoot: { - { - prepareToCommitHoistables(); - var previousHoistableRoot = currentHoistableRoot; - currentHoistableRoot = getHoistableRoot(root.containerInfo); - recursivelyTraverseMutationEffects(root, finishedWork); - currentHoistableRoot = previousHoistableRoot; - commitReconciliationEffects(finishedWork); - } - - if (flags & Update) { - { - if (current !== null) { - var prevRootState = current.memoizedState; + resetContextDependencies(); + executionContext = prevExecutionContext; + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); - if (prevRootState.isDehydrated) { - try { - commitHydratedContainer(root.containerInfo); - } catch (error) { - captureCommitPhaseError( - finishedWork, - finishedWork.return, - error - ); - } - } - } - } - } + if (workInProgress !== null) { + // This is a sync render, so we should have finished the whole tree. + throw new Error( + "Cannot commit an incomplete root. This error is likely caused by a " + + "bug in React. Please file an issue." + ); + } - return; + { + if (enableDebugTracing) { + logRenderStopped(); } + } - case HostPortal: { - { - var _previousHoistableRoot = currentHoistableRoot; - currentHoistableRoot = getHoistableRoot( - finishedWork.stateNode.containerInfo - ); - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - currentHoistableRoot = _previousHoistableRoot; - } + if (enableSchedulingProfiler) { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - return; - } + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - case SuspenseComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - var offscreenFiber = finishedWork.child; + finishQueueingConcurrentUpdates(); + return workInProgressRootExitStatus; +} // The work loop is an extremely hot path. Tell Closure not to inline it. - if (offscreenFiber.flags & Visibility) { - var newState = offscreenFiber.memoizedState; - var isHidden = newState !== null; +/** @noinline */ - if (isHidden) { - var wasHidden = - offscreenFiber.alternate !== null && - offscreenFiber.alternate.memoizedState !== null; +function workLoopSync() { + // Perform work without checking if we need to yield between fiber. + while (workInProgress !== null) { + performUnitOfWork(workInProgress); + } +} - if (!wasHidden) { - // TODO: Move to passive phase - markCommitTimeOfFallback(); - } - } - } +function renderRootConcurrent(root, lanes) { + var prevExecutionContext = executionContext; + executionContext |= RenderContext; + var prevDispatcher = pushDispatcher(root.containerInfo); + var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack + // and prepare a fresh one. Otherwise we'll continue where we left off. - if (flags & Update) { - try { - commitSuspenseCallback(finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { + { + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; - var wakeables = finishedWork.updateQueue; + if (memoizedUpdaters.size > 0) { + restorePendingUpdaters(root, workInProgressRootRenderLanes); + memoizedUpdaters.clear(); + } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. + // If we bailout on this work, we'll move them back (like above). + // It's important to move them now in case the work spawns more work at the same priority with different updaters. + // That way we can keep the current update and future updates separate. - if (wakeables !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, wakeables); - } + movePendingFibersToMemoized(root, lanes); } + } - return; + workInProgressTransitions = getTransitionsForLanes(root, lanes); + resetRenderTimer(); + prepareFreshStack(root, lanes); + } + + { + if (enableDebugTracing) { + logRenderStarted(lanes); } + } - case OffscreenComponent: { - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(current, current.return); - } - } + if (enableSchedulingProfiler) { + markRenderStarted(lanes); + } - var _newState = finishedWork.memoizedState; + outer: do { + try { + if ( + workInProgressSuspendedReason !== NotSuspended && + workInProgress !== null + ) { + // The work loop is suspended. We need to either unwind the stack or + // replay the suspended component. + var unitOfWork = workInProgress; + var thrownValue = workInProgressThrownValue; - var _isHidden = _newState !== null; + switch (workInProgressSuspendedReason) { + case SuspendedOnError: { + // Unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + unwindSuspendedUnitOfWork(unitOfWork, thrownValue); + break; + } - var _wasHidden = current !== null && current.memoizedState !== null; + case SuspendedOnData: { + var thenable = thrownValue; - if (finishedWork.mode & ConcurrentMode) { - // Before committing the children, track on the stack whether this - // offscreen subtree was already hidden, so that we don't unmount the - // effects again. - var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden; - var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden || _isHidden; - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden || _wasHidden; - recursivelyTraverseMutationEffects(root, finishedWork); - offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden; - offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden; - } else { - recursivelyTraverseMutationEffects(root, finishedWork); - } + if (isThenableResolved(thenable)) { + // The data resolved. Try rendering the component again. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + replaySuspendedUnitOfWork(unitOfWork); + break; + } // The work loop is suspended on data. We should wait for it to + // resolve before continuing to render. + // TODO: Handle the case where the promise resolves synchronously. + // Usually this is handled when we instrument the promise to add a + // `status` field, but if the promise already has a status, we won't + // have added a listener until right here. - commitReconciliationEffects(finishedWork); - var offscreenInstance = finishedWork.stateNode; // TODO: Add explicit effect flag to set _current. + var onResolution = function () { + // Check if the root is still suspended on this promise. + if ( + workInProgressSuspendedReason === SuspendedOnData && + workInProgressRoot === root + ) { + // Mark the root as ready to continue rendering. + workInProgressSuspendedReason = SuspendedAndReadyToContinue; + } // Ensure the root is scheduled. We should do this even if we're + // currently working on a different root, so that we resume + // rendering later. - offscreenInstance._current = finishedWork; // Offscreen stores pending changes to visibility in `_pendingVisibility`. This is - // to support batching of `attach` and `detach` calls. + ensureRootIsScheduled(root, now$1()); + }; - offscreenInstance._visibility &= ~OffscreenDetached; - offscreenInstance._visibility |= - offscreenInstance._pendingVisibility & OffscreenDetached; + thenable.then(onResolution, onResolution); + break outer; + } - if (flags & Visibility) { - // Track the current state on the Offscreen instance so we can - // read it during an event - if (_isHidden) { - offscreenInstance._visibility &= ~OffscreenVisible; - } else { - offscreenInstance._visibility |= OffscreenVisible; - } + case SuspendedOnImmediate: { + // If this fiber just suspended, it's possible the data is already + // cached. Yield to the main thread to give it a chance to ping. If + // it does, we can retry immediately without unwinding the stack. + workInProgressSuspendedReason = SuspendedAndReadyToContinue; + break outer; + } - if (_isHidden) { - var isUpdate = current !== null; - var wasHiddenByAncestorOffscreen = - offscreenSubtreeIsHidden || offscreenSubtreeWasHidden; // Only trigger disapper layout effects if: - // - This is an update, not first mount. - // - This Offscreen was not hidden before. - // - Ancestor Offscreen was not hidden in previous commit. + case SuspendedAndReadyToContinue: { + var _thenable = thrownValue; - if (isUpdate && !_wasHidden && !wasHiddenByAncestorOffscreen) { - if ((finishedWork.mode & ConcurrentMode) !== NoMode) { - // Disappear the layout effects of all the children - recursivelyTraverseDisappearLayoutEffects(finishedWork); + if (isThenableResolved(_thenable)) { + // The data resolved. Try rendering the component again. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + replaySuspendedUnitOfWork(unitOfWork); + } else { + // Otherwise, unwind then continue with the normal work loop. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + unwindSuspendedUnitOfWork(unitOfWork, thrownValue); } - } - } // Offscreen with manual mode manages visibility manually. - if (!isOffscreenManual(finishedWork)) { - // TODO: This needs to run whenever there's an insertion or update - // inside a hidden Offscreen tree. - hideOrUnhideAllChildren(finishedWork, _isHidden); - } - } // TODO: Move to passive phase + break; + } - if (flags & Update) { - var offscreenQueue = finishedWork.updateQueue; + case SuspendedOnDeprecatedThrowPromise: { + // Suspended by an old implementation that uses the `throw promise` + // pattern. The newer replaying behavior can cause subtle issues + // like infinite ping loops. So we maintain the old behavior and + // always unwind. + workInProgressSuspendedReason = NotSuspended; + workInProgressThrownValue = null; + unwindSuspendedUnitOfWork(unitOfWork, thrownValue); + break; + } - if (offscreenQueue !== null) { - var _wakeables = offscreenQueue.wakeables; + case SuspendedOnHydration: { + // Selective hydration. An update flowed into a dehydrated tree. + // Interrupt the current render so the work loop can switch to the + // hydration lane. + resetWorkInProgressStack(); + workInProgressRootExitStatus = RootDidNotComplete; + break outer; + } - if (_wakeables !== null) { - offscreenQueue.wakeables = null; - attachSuspenseRetryListeners(finishedWork, _wakeables); + default: { + throw new Error( + "Unexpected SuspendedReason. This is a bug in React." + ); } } } - return; - } - - case SuspenseListComponent: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - - if (flags & Update) { - var _wakeables2 = finishedWork.updateQueue; - - if (_wakeables2 !== null) { - finishedWork.updateQueue = null; - attachSuspenseRetryListeners(finishedWork, _wakeables2); - } + if (true && ReactCurrentActQueue.current !== null) { + // `act` special case: If we're inside an `act` scope, don't consult + // `shouldYield`. Always keep working until the render is complete. + // This is not just an optimization: in a unit test environment, we + // can't trust the result of `shouldYield`, because the host I/O is + // likely mocked. + workLoopSync(); + } else { + workLoopConcurrent(); } - return; + break; + } catch (thrownValue) { + handleThrow(root, thrownValue); } + } while (true); - case ScopeComponent: { - { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); // TODO: This is a temporary solution that allowed us to transition away - // from React Flare on www. - - if (flags & Ref) { - if (current !== null) { - safelyDetachRef(finishedWork, finishedWork.return); - } - - safelyAttachRef(finishedWork, finishedWork.return); - } - - if (flags & Update) { - var scopeInstance = finishedWork.stateNode; - prepareScopeUpdate(scopeInstance, finishedWork); - } - } + resetContextDependencies(); + popDispatcher(prevDispatcher); + popCacheDispatcher(prevCacheDispatcher); + executionContext = prevExecutionContext; - return; + { + if (enableDebugTracing) { + logRenderStopped(); } + } // Check if the tree has completed. - default: { - recursivelyTraverseMutationEffects(root, finishedWork); - commitReconciliationEffects(finishedWork); - return; + if (workInProgress !== null) { + // Still work remaining. + if (enableSchedulingProfiler) { + markRenderYielded(); } - } -} -function commitReconciliationEffects(finishedWork) { - // Placement effects (insertions, reorders) can be scheduled on any fiber - // type. They needs to happen after the children effects have fired, but - // before the effects on this fiber have fired. - var flags = finishedWork.flags; + return RootInProgress; + } else { + // Completed the tree. + if (enableSchedulingProfiler) { + markRenderStopped(); + } // Set this to null to indicate there's no in-progress render. - if (flags & Placement) { - try { - commitPlacement(finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } // 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. + workInProgressRoot = null; + workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. - finishedWork.flags &= ~Placement; - } + finishQueueingConcurrentUpdates(); // Return the final exit status. - if (flags & Hydrating) { - finishedWork.flags &= ~Hydrating; + return workInProgressRootExitStatus; } } +/** @noinline */ -function commitLayoutEffects(finishedWork, root, committedLanes) { - inProgressLanes = committedLanes; - inProgressRoot = root; - var current = finishedWork.alternate; - commitLayoutEffectOnFiber(root, current, finishedWork); - inProgressLanes = null; - inProgressRoot = null; +function workLoopConcurrent() { + // Perform work until Scheduler asks us to yield + while (workInProgress !== null && !shouldYield()) { + // $FlowFixMe[incompatible-call] found when upgrading Flow + performUnitOfWork(workInProgress); + } } -function recursivelyTraverseLayoutEffects(root, parentFiber, lanes) { - var prevDebugFiber = getCurrentFiber(); - - if (parentFiber.subtreeFlags & LayoutMask) { - var child = parentFiber.child; +function performUnitOfWork(unitOfWork) { + // 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 = unitOfWork.alternate; + setCurrentFiber(unitOfWork); + var next; - while (child !== null) { - setCurrentFiber(child); - var current = child.alternate; - commitLayoutEffectOnFiber(root, current, child); - child = child.sibling; - } + if ((unitOfWork.mode & ProfileMode) !== NoMode) { + startProfilerTimer(unitOfWork); + next = beginWork(current, unitOfWork, renderLanes); + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } else { + next = beginWork(current, unitOfWork, renderLanes); } - setCurrentFiber(prevDebugFiber); -} + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; -function disappearLayoutEffects(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case MemoComponent: - case SimpleMemoComponent: { - // TODO (Offscreen) Check: flags & LayoutStatic - if (shouldProfile(finishedWork)) { - try { - startLayoutEffectTimer(); - commitHookEffectListUnmount( - Layout, - finishedWork, - finishedWork.return - ); - } finally { - recordLayoutEffectDuration(finishedWork); - } - } else { - commitHookEffectListUnmount(Layout, finishedWork, finishedWork.return); - } + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; - } + ReactCurrentOwner$1.current = null; +} - case ClassComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var instance = finishedWork.stateNode; +function replaySuspendedUnitOfWork(unitOfWork) { + // This is a fork of performUnitOfWork specifcally for replaying a fiber that + // just suspended. + // + var current = unitOfWork.alternate; + setCurrentFiber(unitOfWork); + var next; + setCurrentFiber(unitOfWork); + var isProfilingMode = (unitOfWork.mode & ProfileMode) !== NoMode; - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount( - finishedWork, - finishedWork.return, - instance - ); - } + if (isProfilingMode) { + startProfilerTimer(unitOfWork); + } - recursivelyTraverseDisappearLayoutEffects(finishedWork); - break; + switch (unitOfWork.tag) { + case IndeterminateComponent: { + // Because it suspended with `use`, we can assume it's a + // function component. + unitOfWork.tag = FunctionComponent; // Fallthrough to the next branch. } + // eslint-disable-next-line no-fallthrough - case HostHoistable: - case HostSingleton: - case HostComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - recursivelyTraverseDisappearLayoutEffects(finishedWork); + case FunctionComponent: + case ForwardRef: { + // Resolve `defaultProps`. This logic is copied from `beginWork`. + // TODO: Consider moving this switch statement into that module. Also, + // could maybe use this as an opportunity to say `use` doesn't work with + // `defaultProps` :) + var Component = unitOfWork.type; + var unresolvedProps = unitOfWork.pendingProps; + var resolvedProps = + unitOfWork.elementType === Component + ? unresolvedProps + : resolveDefaultProps(Component, unresolvedProps); + next = replayFunctionComponent( + current, + unitOfWork, + resolvedProps, + Component, + workInProgressRootRenderLanes + ); break; } - case OffscreenComponent: { - // TODO (Offscreen) Check: flags & RefStatic - safelyDetachRef(finishedWork, finishedWork.return); - var isHidden = finishedWork.memoizedState !== null; - - if (isHidden); - else { - recursivelyTraverseDisappearLayoutEffects(finishedWork); - } - + case SimpleMemoComponent: { + var _Component = unitOfWork.type; + var nextProps = unitOfWork.pendingProps; + next = replayFunctionComponent( + current, + unitOfWork, + nextProps, + _Component, + workInProgressRootRenderLanes + ); break; } default: { - recursivelyTraverseDisappearLayoutEffects(finishedWork); + // Other types besides function components are reset completely before + // being replayed. Currently this only happens when a Usable type is + // reconciled — the reconciler will suspend. + // + // We reset the fiber back to its original state; however, this isn't + // a full "unwind" because we're going to reuse the promises that were + // reconciled previously. So it's intentional that we don't call + // resetSuspendedWorkLoopOnUnwind here. + unwindInterruptedWork(current, unitOfWork); + unitOfWork = workInProgress = resetWorkInProgress( + unitOfWork, + renderLanes + ); + next = beginWork(current, unitOfWork, renderLanes); break; } } + + if (isProfilingMode) { + stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); + } // The begin phase finished successfully without suspending. Return to the + // normal work loop. + + resetCurrentFiber(); + unitOfWork.memoizedProps = unitOfWork.pendingProps; + + if (next === null) { + // If this doesn't spawn new work, complete the current work. + completeUnitOfWork(unitOfWork); + } else { + workInProgress = next; + } + + ReactCurrentOwner$1.current = null; } -function recursivelyTraverseDisappearLayoutEffects(parentFiber) { - // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - var child = parentFiber.child; +function unwindSuspendedUnitOfWork(unitOfWork, thrownValue) { + // This is a fork of performUnitOfWork specifcally for unwinding a fiber + // that threw an exception. + // + // Return to the normal work loop. This will unwind the stack, and potentially + // result in showing a fallback. + resetSuspendedWorkLoopOnUnwind(); + var returnFiber = unitOfWork.return; - while (child !== null) { - disappearLayoutEffects(child); - child = child.sibling; + if (returnFiber === null || workInProgressRoot === null) { + // Expected to be working on a non-root fiber. This is a fatal error + // because there's no ancestor that can handle it; the root is + // supposed to capture all errors that weren't caught by an error + // boundary. + workInProgressRootExitStatus = RootFatalErrored; + workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next + // sibling, or the parent if there are no siblings. But since the root + // has no siblings nor a parent, we set it to null. Usually this is + // handled by `completeUnitOfWork` or `unwindWork`, but since we're + // intentionally not calling those, we need set it here. + // TODO: Consider calling `unwindWork` to pop the contexts. + + workInProgress = null; + return; } + + try { + // Find and mark the nearest Suspense or error boundary that can handle + // this "exception". + throwException( + workInProgressRoot, + returnFiber, + unitOfWork, + thrownValue, + workInProgressRootRenderLanes + ); + } catch (error) { + // We had trouble processing the error. An example of this happening is + // when accessing the `componentDidCatch` property of an error boundary + // throws an error. A weird edge case. There's a regression test for this. + // To prevent an infinite loop, bubble the error up to the next parent. + workInProgress = returnFiber; + throw error; + } // Return to the normal work loop. + + completeUnitOfWork(unitOfWork); } -function reappearLayoutEffects( - finishedRoot, - current, - finishedWork, // This function visits both newly finished work and nodes that were re-used - // from a previously committed tree. We cannot check non-static flags if the - // node was reused. - includeWorkInProgressEffects -) { - // Turn on layout effects in a tree that previously disappeared. - var flags = finishedWork.flags; +function completeUnitOfWork(unitOfWork) { + // 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. + var completedWork = unitOfWork; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check flags & LayoutStatic + do { + // 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 = completedWork.alternate; + var returnFiber = completedWork.return; // Check if the work completed or if something threw. - commitHookLayoutEffects(finishedWork, Layout); - break; - } + if ((completedWork.flags & Incomplete) === NoFlags$1) { + setCurrentFiber(completedWork); + var next = void 0; - case ClassComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Check for LayoutStatic flag + if ((completedWork.mode & ProfileMode) === NoMode) { + next = completeWork(current, completedWork, renderLanes); + } else { + startProfilerTimer(completedWork); + next = completeWork(current, completedWork, renderLanes); // Update render duration assuming we didn't error. - var instance = finishedWork.stateNode; + stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); + } - if (typeof instance.componentDidMount === "function") { - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } // Commit any callbacks that would have fired while the component - // was hidden. + resetCurrentFiber(); - var updateQueue = finishedWork.updateQueue; + if (next !== null) { + // Completing this fiber spawned new work. Work on that next. + workInProgress = next; + return; + } + } else { + // 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(current, completedWork); // Because this fiber did not complete, don't reset its lanes. - if (updateQueue !== null) { - commitHiddenCallbacks(updateQueue, instance); - } // If this is newly finished work, check for setState callbacks + if (_next !== null) { + // If completing this work spawned new work, do that next. We'll come + // back here again. + // Since we're restarting, remove anything that is not a host effect + // from the effect tag. + _next.flags &= HostEffectMask; + workInProgress = _next; + return; + } - if (includeWorkInProgressEffects && flags & Callback) { - commitClassCallbacks(finishedWork); - } // TODO: Check flags & RefStatic + if ((completedWork.mode & ProfileMode) !== NoMode) { + // Record the render duration for the fiber that errored. + stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing. - safelyAttachRef(finishedWork, finishedWork.return); - break; + var actualDuration = completedWork.actualDuration; + var child = completedWork.child; + + while (child !== null) { + // $FlowFixMe[unsafe-addition] addition with possible null/undefined value + actualDuration += child.actualDuration; + child = child.sibling; + } + + completedWork.actualDuration = actualDuration; + } + + if (returnFiber !== null) { + // Mark the parent fiber as incomplete and clear its subtree flags. + returnFiber.flags |= Incomplete; + returnFiber.subtreeFlags = NoFlags$1; + returnFiber.deletions = null; + } else { + // We've unwound all the way to the root. + workInProgressRootExitStatus = RootDidNotComplete; + workInProgress = null; + return; + } } - // Unlike commitLayoutEffectsOnFiber, we don't need to handle HostRoot - // because this function only visits nodes that are inside an - // Offscreen fiber. - // case HostRoot: { - // ... - // } - case HostHoistable: - case HostSingleton: - case HostComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // 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. + var siblingFiber = completedWork.sibling; - if (includeWorkInProgressEffects && current === null && flags & Update) { - commitHostComponentMount(finishedWork); - } // TODO: Check flags & Ref + if (siblingFiber !== null) { + // If there is more work to do in this returnFiber, do that next. + workInProgress = siblingFiber; + return; + } // Otherwise, return to the parent + // $FlowFixMe[incompatible-type] we bail out when we get a null + + completedWork = returnFiber; // Update the next thing we're working on in case something throws. + + workInProgress = completedWork; + } while (completedWork !== null); // We've reached the root. + + if (workInProgressRootExitStatus === RootInProgress) { + workInProgressRootExitStatus = RootCompleted; + } +} + +function commitRoot(root, recoverableErrors, transitions) { + // TODO: This no longer makes any sense. We already wrap the mutation and + // layout phases. Should be able to remove. + var previousUpdateLanePriority = getCurrentUpdatePriority(); + var prevTransition = ReactCurrentBatchConfig$1.transition; + + try { + ReactCurrentBatchConfig$1.transition = null; + setCurrentUpdatePriority(DiscreteEventPriority); + commitRootImpl( + root, + recoverableErrors, + transitions, + previousUpdateLanePriority + ); + } finally { + ReactCurrentBatchConfig$1.transition = prevTransition; + setCurrentUpdatePriority(previousUpdateLanePriority); + } + + return null; +} + +function commitRootImpl( + root, + recoverableErrors, + transitions, + renderPriorityLevel +) { + do { + // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which + // means `flushPassiveEffects` will sometimes result in additional + // passive effects. So we need to keep flushing in a loop until there are + // no more pending effects. + // TODO: Might be better if `flushPassiveEffects` did not automatically + // flush synchronous work at the end, to avoid factoring hazards like this. + flushPassiveEffects(); + } while (rootWithPendingPassiveEffects !== null); - safelyAttachRef(finishedWork, finishedWork.return); - break; - } + flushRenderPhaseStrictModeWarningsInDEV(); - case Profiler: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Profiler updates should work with Offscreen + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Should not already be working."); + } - if (includeWorkInProgressEffects && flags & Update) { - commitProfilerUpdate(finishedWork, current); - } + var finishedWork = root.finishedWork; + var lanes = root.finishedLanes; - break; + { + if (enableDebugTracing) { + logCommitStarted(lanes); } + } - case SuspenseComponent: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); // TODO: Figure out how Suspense hydration callbacks should work - // with Offscreen. + if (enableSchedulingProfiler) { + markCommitStarted(lanes); + } - if (includeWorkInProgressEffects && flags & Update) { - commitSuspenseHydrationCallbacks(finishedRoot, finishedWork); + if (finishedWork === null) { + { + if (enableDebugTracing) { + logCommitStopped(); } - - break; } - case OffscreenComponent: { - var offscreenState = finishedWork.memoizedState; - var isHidden = offscreenState !== null; - - if (isHidden); - else { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - } // TODO: Check flags & Ref - - safelyAttachRef(finishedWork, finishedWork.return); - break; + if (enableSchedulingProfiler) { + markCommitStopped(); } - default: { - recursivelyTraverseReappearLayoutEffects( - finishedRoot, - finishedWork, - includeWorkInProgressEffects - ); - break; + return null; + } else { + { + if (lanes === NoLanes) { + error( + "root.finishedLanes should not be empty during a commit. This is a " + + "bug in React." + ); + } } } -} - -function recursivelyTraverseReappearLayoutEffects( - finishedRoot, - parentFiber, - includeWorkInProgressEffects -) { - // This function visits both newly finished work and nodes that were re-used - // from a previously committed tree. We cannot check non-static flags if the - // node was reused. - var childShouldIncludeWorkInProgressEffects = - includeWorkInProgressEffects && - (parentFiber.subtreeFlags & LayoutMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; + root.finishedWork = null; + root.finishedLanes = NoLanes; - while (child !== null) { - var current = child.alternate; - reappearLayoutEffects( - finishedRoot, - current, - child, - childShouldIncludeWorkInProgressEffects + if (finishedWork === root.current) { + throw new Error( + "Cannot commit the same tree as before. This error is likely caused by " + + "a bug in React. Please file an issue." ); - child = child.sibling; - } + } // commitRoot never returns a continuation; it always finishes synchronously. + // So we can clear these now to allow a new callback to be scheduled. - setCurrentFiber(prevDebugFiber); -} + root.callbackNode = null; + root.callbackPriority = NoLane; // Check which lanes no longer have any work scheduled on them, and mark + // those as finished. -function commitHookPassiveMountEffects(finishedWork, hookFlags) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); + var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes); // Make sure to account for lanes that were updated by a concurrent event + // during the render phase; don't mark them as finished. - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } + var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); + remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); + markRootFinished(root, remainingLanes); - recordPassiveEffectDuration(finishedWork); - } else { - try { - commitHookEffectListMount(hookFlags, finishedWork); - } catch (error) { - captureCommitPhaseError(finishedWork, finishedWork.return, error); - } - } -} + if (root === workInProgressRoot) { + // We can reset these now that they are finished. + workInProgressRoot = null; + workInProgress = null; + workInProgressRootRenderLanes = NoLanes; + } // If there are pending passive effects, schedule a callback to process them. + // Do this as early as possible, so it is queued before anything else that + // might get scheduled in the commit phase. (See #16714.) + // TODO: Delete all other places that schedule the passive effect callback + // They're redundant. -function commitOffscreenPassiveMountEffects(current, finishedWork, instance) { - { - var previousCache = null; + if ( + (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || + (finishedWork.flags & PassiveMask) !== NoFlags$1 + ) { + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want + // to store it in pendingPassiveTransitions until they get processed + // We need to pass this through as an argument to commitRoot + // because workInProgressTransitions might have changed between + // the previous render and commit if we throttle the commit + // with setTimeout - if ( - current !== null && - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - previousCache = current.memoizedState.cachePool.pool; + pendingPassiveTransitions = transitions; + scheduleCallback(NormalPriority$1, function () { + flushPassiveEffects(); // This render triggered passive effects: release the root cache pool + // *after* passive effects fire to avoid freeing a cache pool that may + // be referenced by a node in the tree (HostRoot, Cache boundary etc) + + return null; + }); } + } // Check if there are any effects in the whole tree. + // TODO: This is left over from the effect list implementation, where we had + // to check for the existence of `firstEffect` to satisfy Flow. I think the + // only other reason this optimization exists is because it affects profiling. + // Reconsider whether this is necessary. - var nextCache = null; + var subtreeHasEffects = + (finishedWork.subtreeFlags & + (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== + NoFlags$1; + var rootHasEffect = + (finishedWork.flags & + (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== + NoFlags$1; - if ( - finishedWork.memoizedState !== null && - finishedWork.memoizedState.cachePool !== null - ) { - nextCache = finishedWork.memoizedState.cachePool.pool; - } // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). + if (subtreeHasEffects || rootHasEffect) { + var prevTransition = ReactCurrentBatchConfig$1.transition; + ReactCurrentBatchConfig$1.transition = null; + var previousPriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var prevExecutionContext = executionContext; + executionContext |= CommitContext; // Reset this to null before calling lifecycles - if (nextCache !== previousCache) { - if (nextCache != null) { - retainCache(nextCache); - } + ReactCurrentOwner$1.current = null; // The commit phase is broken into several sub-phases. We do a separate pass + // of the effect list for each phase: all mutation effects come before all + // layout effects, and so on. + // The first phase a "before mutation" phase. We use this phase to read the + // state of the host tree right before we mutate it. This is where + // getSnapshotBeforeUpdate is called. - if (previousCache != null) { - releaseCache(previousCache); - } + var shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects( + root, + finishedWork + ); + + { + // Mark the current commit time to be shared by all Profilers in this + // batch. This enables them to be grouped later. + recordCommitTime(); } - } - if (enableTransitionTracing) { - // TODO: Pre-rendering should not be counted as part of a transition. We - // may add separate logs for pre-rendering, but it's not part of the - // primary metrics. - var offscreenState = finishedWork.memoizedState; - var queue = finishedWork.updateQueue; - var isHidden = offscreenState !== null; + if (enableProfilerNestedUpdateScheduledHook) { + // Track the root here, rather than in commitLayoutEffects(), because of ref setters. + // Updates scheduled during ref detachment should also be flagged. + rootCommittingMutationOrLayoutEffects = root; + } // The next phase is the mutation phase, where we mutate the host tree. - if (queue !== null) { - if (isHidden) { - var transitions = queue.transitions; + commitMutationEffects(root, finishedWork, lanes); - if (transitions !== null) { - transitions.forEach(function (transition) { - // Add all the transitions saved in the update queue during - // the render phase (ie the transitions associated with this boundary) - // into the transitions set. - if (instance._transitions === null) { - instance._transitions = new Set(); - } + { + if (shouldFireAfterActiveInstanceBlur) { + afterActiveInstanceBlur(); + } + } - instance._transitions.add(transition); - }); - } + resetAfterCommit(); // The work-in-progress tree is now the current tree. This must come after + // the mutation phase, so that the previous tree is still current during + // componentWillUnmount, but before the layout phase, so that the finished + // work is current during componentDidMount/Update. - var markerInstances = queue.markerInstances; + root.current = finishedWork; // The next phase is the layout phase, where we call effects that read + // the host tree after it's been mutated. The idiomatic use case for this is + // layout, but class component lifecycles also fire here for legacy reasons. - if (markerInstances !== null) { - markerInstances.forEach(function (markerInstance) { - var markerTransitions = markerInstance.transitions; // There should only be a few tracing marker transitions because - // they should be only associated with the transition that - // caused them + { + if (enableDebugTracing) { + logLayoutEffectsStarted(lanes); + } + } - if (markerTransitions !== null) { - markerTransitions.forEach(function (transition) { - if (instance._transitions === null) { - instance._transitions = new Set(); - } else if (instance._transitions.has(transition)) { - if (markerInstance.pendingBoundaries === null) { - markerInstance.pendingBoundaries = new Map(); - } + if (enableSchedulingProfiler) { + markLayoutEffectsStarted(lanes); + } - if (instance._pendingMarkers === null) { - instance._pendingMarkers = new Set(); - } + commitLayoutEffects(finishedWork, root, lanes); - instance._pendingMarkers.add(markerInstance); - } - }); - } - }); - } + { + if (enableDebugTracing) { + logLayoutEffectsStopped(); } + } - finishedWork.updateQueue = null; + if (enableSchedulingProfiler) { + markLayoutEffectsStopped(); } - commitTransitionProgress(finishedWork); // TODO: Refactor this into an if/else branch + if (enableProfilerNestedUpdateScheduledHook) { + rootCommittingMutationOrLayoutEffects = null; + } // Tell Scheduler to yield at the end of the frame, so the browser has an + // opportunity to paint. - if (!isHidden) { - instance._transitions = null; - instance._pendingMarkers = null; - } - } -} + requestPaint(); + executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. -function commitCachePassiveMountEffect(current, finishedWork) { - { - var previousCache = null; + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig$1.transition = prevTransition; + } else { + // No effects. + root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were + // no effects. + // TODO: Maybe there's a better way to report this. - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; + { + recordCommitTime(); } + } - var nextCache = finishedWork.memoizedState.cache; // Retain/release the cache. In theory the cache component - // could be "borrowing" a cache instance owned by some parent, - // in which case we could avoid retaining/releasing. But it - // is non-trivial to determine when that is the case, so we - // always retain/release. + var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; - if (nextCache !== previousCache) { - retainCache(nextCache); + if (rootDoesHavePassiveEffects) { + // This commit has passive effects. Stash a reference to them. But don't + // schedule a callback until after flushing layout work. + rootDoesHavePassiveEffects = false; + rootWithPendingPassiveEffects = root; + pendingPassiveEffectsLanes = lanes; + } else { + // There were no passive effects, so we can immediately release the cache + // pool for this render. + releaseRootPooledCache(root, remainingLanes); - if (previousCache != null) { - releaseCache(previousCache); - } + { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; } - } -} + } // Read this again, since an effect might have updated it -function commitTracingMarkerPassiveMountEffect(finishedWork) { - // Get the transitions that were initiatized during the render - // and add a start transition callback for each of them - // We will only call this on initial mount of the tracing marker - // only if there are no suspense children - var instance = finishedWork.stateNode; + remainingLanes = root.pendingLanes; // Check if there's remaining work on this root + // TODO: This is part of the `componentDidCatch` implementation. Its purpose + // is to detect whether something might have called setState inside + // `componentDidCatch`. The mechanism is known to be flawed because `setState` + // inside `componentDidCatch` is itself flawed — that's why we recommend + // `getDerivedStateFromError` instead. However, it could be improved by + // checking if remainingLanes includes Sync work, instead of whether there's + // any work remaining at all (which would also include stuff like Suspense + // retries or transitions). It's been like this for a while, though, so fixing + // it probably isn't that urgent. - if (instance.transitions !== null && instance.pendingBoundaries === null) { - addMarkerCompleteCallbackToPendingTransition( - finishedWork.memoizedProps.name, - instance.transitions - ); - instance.transitions = null; - instance.pendingBoundaries = null; - instance.aborts = null; - instance.name = null; + if (remainingLanes === NoLanes) { + // If there's no remaining work, we can clear the set of already failed + // error boundaries. + legacyErrorBoundariesThatAlreadyFailed = null; } -} -function commitPassiveMountEffects( - root, - finishedWork, - committedLanes, - committedTransitions -) { - setCurrentFiber(finishedWork); - commitPassiveMountOnFiber( - root, - finishedWork, - committedLanes, - committedTransitions - ); - resetCurrentFiber(); -} - -function recursivelyTraversePassiveMountEffects( - root, - parentFiber, - committedLanes, - committedTransitions -) { - var prevDebugFiber = getCurrentFiber(); + { + if (!rootDidHavePassiveEffects) { + commitDoubleInvokeEffectsInDEV(root, false); + } + } - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; + onCommitRoot$1(finishedWork.stateNode, renderPriorityLevel); - while (child !== null) { - setCurrentFiber(child); - commitPassiveMountOnFiber( - root, - child, - committedLanes, - committedTransitions - ); - child = child.sibling; + { + if (isDevToolsPresent) { + root.memoizedUpdaters.clear(); } } - setCurrentFiber(prevDebugFiber); -} - -function commitPassiveMountOnFiber( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions -) { - // When updating this function, also update reconnectPassiveEffects, which does - // most of the same things when an offscreen tree goes from hidden -> visible, - // or when toggling effects inside a hidden tree. - var flags = finishedWork.flags; + { + onCommitRoot(); + } // Always call this before exiting `commitRoot`, to ensure that any + // additional work on this root is scheduled. - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + ensureRootIsScheduled(root, now$1()); - if (flags & Passive$1) { - commitHookPassiveMountEffects(finishedWork, Passive | HasEffect); - } + if (recoverableErrors !== null) { + // There were errors during this render, but recovered from them without + // needing to surface it to the UI. We log them here. + var onRecoverableError = root.onRecoverableError; - break; + for (var i = 0; i < recoverableErrors.length; i++) { + var recoverableError = recoverableErrors[i]; + var errorInfo = makeErrorInfo( + recoverableError.digest, + recoverableError.stack + ); + onRecoverableError(recoverableError.value, errorInfo); } + } - case HostRoot: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + if (hasUncaughtError) { + hasUncaughtError = false; + var error$1 = firstUncaughtError; + firstUncaughtError = null; + throw error$1; + } // If the passive effects are the result of a discrete render, flush them + // synchronously at the end of the current task so that the result is + // immediately observable. Otherwise, we assume that they are not + // order-dependent and do not need to be observed by external systems, so we + // can wait until after paint. + // TODO: We can optimize this by not scheduling the callback earlier. Since we + // currently schedule the callback in multiple places, will wait until those + // are consolidated. - if (flags & Passive$1) { - { - var previousCache = null; + if (includesSyncLane(pendingPassiveEffectsLanes) && root.tag !== LegacyRoot) { + flushPassiveEffects(); + } // Read this again, since a passive effect might have updated it - if (finishedWork.alternate !== null) { - previousCache = finishedWork.alternate.memoizedState.cache; - } + remainingLanes = root.pendingLanes; - var nextCache = finishedWork.memoizedState.cache; // Retain/release the root cache. - // Note that on initial mount, previousCache and nextCache will be the same - // and this retain won't occur. To counter this, we instead retain the HostRoot's - // initial cache when creating the root itself (see createFiberRoot() in - // ReactFiberRoot.js). Subsequent updates that change the cache are reflected - // here, such that previous/next caches are retained correctly. + if (includesSyncLane(remainingLanes)) { + { + markNestedUpdateScheduled(); + } // Count the number of times the root synchronously re-renders without + // finishing. If there are too many, it indicates an infinite update loop. - if (nextCache !== previousCache) { - retainCache(nextCache); + if (root === rootWithNestedUpdates) { + nestedUpdateCount++; + } else { + nestedUpdateCount = 0; + rootWithNestedUpdates = root; + } + } else { + nestedUpdateCount = 0; + } // If layout work was scheduled, flush it now. - if (previousCache != null) { - releaseCache(previousCache); - } - } - } + flushSyncCallbacks(); - if (enableTransitionTracing) { - // Get the transitions that were initiatized during the render - // and add a start transition callback for each of them - var root = finishedWork.stateNode; - var incompleteTransitions = root.incompleteTransitions; // Initial render + { + if (enableDebugTracing) { + logCommitStopped(); + } + } - if (committedTransitions !== null) { - committedTransitions.forEach(function (transition) { - addTransitionStartCallbackToPendingTransition(transition); - }); - clearTransitionsForLanes(finishedRoot, committedLanes); - } + if (enableSchedulingProfiler) { + markCommitStopped(); + } - incompleteTransitions.forEach(function (markerInstance, transition) { - var pendingBoundaries = markerInstance.pendingBoundaries; + if (enableTransitionTracing) { + // We process transitions during passive effects. However, passive effects can be + // processed synchronously during the commit phase as well as asynchronously after + // paint. At the end of the commit phase, we schedule a callback that will be called + // after the next paint. If the transitions have already been processed (passive + // effect phase happened synchronously), we will schedule a callback to process + // the transitions. However, if we don't have any pending transition callbacks, this + // means that the transitions have yet to be processed (passive effects processed after paint) + // so we will store the end time of paint so that we can process the transitions + // and then call the callback via the correct end time. + var prevRootTransitionCallbacks = root.transitionCallbacks; - if (pendingBoundaries === null || pendingBoundaries.size === 0) { - if (markerInstance.aborts === null) { - addTransitionCompleteCallbackToPendingTransition(transition); - } + if (prevRootTransitionCallbacks !== null) { + schedulePostPaintCallback(function (endTime) { + var prevPendingTransitionCallbacks = currentPendingTransitionCallbacks; - incompleteTransitions.delete(transition); - } + if (prevPendingTransitionCallbacks !== null) { + currentPendingTransitionCallbacks = null; + scheduleCallback(IdlePriority, function () { + processTransitionCallbacks( + prevPendingTransitionCallbacks, + endTime, + prevRootTransitionCallbacks + ); }); - clearTransitionsForLanes(finishedRoot, committedLanes); + } else { + currentEndTime = endTime; } - } - - break; + }); } + } - case LegacyHiddenComponent: { - { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions + return null; +} + +function makeErrorInfo(digest, componentStack) { + { + var errorInfo = { + componentStack: componentStack, + digest: digest + }; + Object.defineProperty(errorInfo, "digest", { + configurable: false, + enumerable: true, + get: function () { + error( + 'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + + " This property is deprecated and will be removed in a future version of React." + + " To access the digest of an Error look for this property on the Error instance itself." ); - if (flags & Passive$1) { - var current = finishedWork.alternate; - var instance = finishedWork.stateNode; - commitOffscreenPassiveMountEffects(current, finishedWork, instance); - } + return digest; } + }); + return errorInfo; + } +} - break; - } +function releaseRootPooledCache(root, remainingLanes) { + { + var pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes); - case OffscreenComponent: { - // TODO: Pass `current` as argument to this function - var _instance3 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + if (pooledCacheLanes === NoLanes) { + // None of the remaining work relies on the cache pool. Clear it so + // subsequent requests get a new cache + var pooledCache = root.pooledCache; - if (isHidden) { - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance3._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } - } - } else { - // Tree is visible - if (_instance3._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - } else { - // The effects are currently disconnected. Reconnect them, while also - // firing effects inside newly mounted trees. This also applies to - // the initial render. - _instance3._visibility |= OffscreenPassiveEffectsConnected; - var includeWorkInProgressEffects = - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } + if (pooledCache != null) { + root.pooledCache = null; + releaseCache(pooledCache); } + } + } +} - if (flags & Passive$1) { - var _current = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current, finishedWork, _instance3); - } +function flushPassiveEffects() { + // Returns whether passive effects were flushed. + // TODO: Combine this check with the one in flushPassiveEFfectsImpl. We should + // probably just combine the two functions. I believe they were only separate + // in the first place because we used to wrap it with + // `Scheduler.runWithPriority`, which accepts a function. But now we track the + // priority within React itself, so we can mutate the variable directly. + if (rootWithPendingPassiveEffects !== null) { + // Cache the root since rootWithPendingPassiveEffects is cleared in + // flushPassiveEffectsImpl + var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this + // method can be called from various places, not always from commitRoot + // where the remaining lanes are known - break; - } + var remainingLanes = pendingPassiveEffectsRemainingLanes; + pendingPassiveEffectsRemainingLanes = NoLanes; + var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); + var priority = lowerEventPriority(DefaultEventPriority, renderPriority); + var prevTransition = ReactCurrentBatchConfig$1.transition; + var previousPriority = getCurrentUpdatePriority(); - case CacheComponent: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); + try { + ReactCurrentBatchConfig$1.transition = null; + setCurrentUpdatePriority(priority); + return flushPassiveEffectsImpl(); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig$1.transition = prevTransition; // Once passive effects have run for the tree - giving components a + // chance to retain cache instances they use - release the pooled + // cache at the root (if there is one) - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current2 = finishedWork.alternate; - commitCachePassiveMountEffect(_current2, finishedWork); - } + releaseRootPooledCache(root, remainingLanes); + } + } - break; + return false; +} +function enqueuePendingPassiveProfilerEffect(fiber) { + { + pendingPassiveProfilerEffects.push(fiber); + + if (!rootDoesHavePassiveEffects) { + rootDoesHavePassiveEffects = true; + scheduleCallback(NormalPriority$1, function () { + flushPassiveEffects(); + return null; + }); } + } +} - case TracingMarkerComponent: { - if (enableTransitionTracing) { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); +function flushPassiveEffectsImpl() { + if (rootWithPendingPassiveEffects === null) { + return false; + } // Cache and clear the transitions flag - if (flags & Passive$1) { - commitTracingMarkerPassiveMountEffect(finishedWork); - } + var transitions = pendingPassiveTransitions; + pendingPassiveTransitions = null; + var root = rootWithPendingPassiveEffects; + var lanes = pendingPassiveEffectsLanes; + rootWithPendingPassiveEffects = null; // TODO: This is sometimes out of sync with rootWithPendingPassiveEffects. + // Figure out why and fix it. It's not causing any known issues (probably + // because it's only used for profiling), but it's a refactor hazard. - break; - } // Intentional fallthrough to next branch - } - // eslint-disable-next-line-no-fallthrough + pendingPassiveEffectsLanes = NoLanes; - default: { - recursivelyTraversePassiveMountEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions - ); - break; - } + if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { + throw new Error("Cannot flush passive effects while already rendering."); } -} -function recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions, - includeWorkInProgressEffects -) { - // This function visits both newly finished work and nodes that were re-used - // from a previously committed tree. We cannot check non-static flags if the - // node was reused. - var childShouldIncludeWorkInProgressEffects = - includeWorkInProgressEffects && - (parentFiber.subtreeFlags & PassiveMask) !== NoFlags$1; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic) + { + isFlushingPassiveEffects = true; + didScheduleUpdateDuringPassiveEffects = false; - var prevDebugFiber = getCurrentFiber(); - var child = parentFiber.child; + if (enableDebugTracing) { + logPassiveEffectsStarted(lanes); + } + } - while (child !== null) { - reconnectPassiveEffects( - finishedRoot, - child, - committedLanes, - committedTransitions, - childShouldIncludeWorkInProgressEffects - ); - child = child.sibling; + if (enableSchedulingProfiler) { + markPassiveEffectsStarted(lanes); } - setCurrentFiber(prevDebugFiber); -} + var prevExecutionContext = executionContext; + executionContext |= CommitContext; + commitPassiveUnmountEffects(root.current); + commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects -function reconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, // This function visits both newly finished work and nodes that were re-used - // from a previously committed tree. We cannot check non-static flags if the - // node was reused. - includeWorkInProgressEffects -) { - var flags = finishedWork.flags; + { + var profilerEffects = pendingPassiveProfilerEffects; + pendingPassiveProfilerEffects = []; - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); // TODO: Check for PassiveStatic flag + for (var i = 0; i < profilerEffects.length; i++) { + var fiber = profilerEffects[i]; + commitPassiveEffectDurations(root, fiber); + } + } - commitHookPassiveMountEffects(finishedWork, Passive); - break; + { + if (enableDebugTracing) { + logPassiveEffectsStopped(); } - // Unlike commitPassiveMountOnFiber, we don't need to handle HostRoot - // because this function only visits nodes that are inside an - // Offscreen fiber. - // case HostRoot: { - // ... - // } + } - case LegacyHiddenComponent: { - { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); + if (enableSchedulingProfiler) { + markPassiveEffectsStopped(); + } - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var current = finishedWork.alternate; - var instance = finishedWork.stateNode; - commitOffscreenPassiveMountEffects(current, finishedWork, instance); - } - } + { + commitDoubleInvokeEffectsInDEV(root, true); + } - break; - } + executionContext = prevExecutionContext; + flushSyncCallbacks(); - case OffscreenComponent: { - var _instance4 = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + if (enableTransitionTracing) { + var prevPendingTransitionCallbacks = currentPendingTransitionCallbacks; + var prevRootTransitionCallbacks = root.transitionCallbacks; + var prevEndTime = currentEndTime; - if (isHidden) { - if (_instance4._visibility & OffscreenPassiveEffectsConnected) { - // The effects are currently connected. Update them. - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } else { - if (finishedWork.mode & ConcurrentMode) { - // The effects are currently disconnected. Since the tree is hidden, - // don't connect them. This also applies to the initial render. - { - // "Atomic" effects are ones that need to fire on every commit, - // even during pre-rendering. An example is updating the reference - // count on cache instances. - recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - finishedWork - ); - } - } else { - // Legacy Mode: Fire the effects even if the tree is hidden. - _instance4._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - } - } - } else { - // Tree is visible - // Since we're already inside a reconnecting tree, it doesn't matter - // whether the effects are currently connected. In either case, we'll - // continue traversing the tree and firing all the effects. - // - // We do need to set the "connected" flag on the instance, though. - _instance4._visibility |= OffscreenPassiveEffectsConnected; - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects + if ( + prevPendingTransitionCallbacks !== null && + prevRootTransitionCallbacks !== null && + prevEndTime !== null + ) { + currentPendingTransitionCallbacks = null; + currentEndTime = null; + scheduleCallback(IdlePriority, function () { + processTransitionCallbacks( + prevPendingTransitionCallbacks, + prevEndTime, + prevRootTransitionCallbacks ); - } + }); + } + } - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current3 = finishedWork.alternate; - commitOffscreenPassiveMountEffects(_current3, finishedWork, _instance4); + { + // If additional passive effects were scheduled, increment a counter. If this + // exceeds the limit, we'll fire a warning. + if (didScheduleUpdateDuringPassiveEffects) { + if (root === rootWithPassiveNestedUpdates) { + nestedPassiveUpdateCount++; + } else { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = root; } - - break; + } else { + nestedPassiveUpdateCount = 0; } - case CacheComponent: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - - if (includeWorkInProgressEffects && flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current4 = finishedWork.alternate; - commitCachePassiveMountEffect(_current4, finishedWork); - } + isFlushingPassiveEffects = false; + didScheduleUpdateDuringPassiveEffects = false; + } // TODO: Move to commitPassiveMountEffects - break; - } + onPostCommitRoot(root); - case TracingMarkerComponent: { - if (enableTransitionTracing) { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); + { + var stateNode = root.current.stateNode; + stateNode.effectDuration = 0; + stateNode.passiveEffectDuration = 0; + } - if (includeWorkInProgressEffects && flags & Passive$1) { - commitTracingMarkerPassiveMountEffect(finishedWork); - } + return true; +} - break; - } // Intentional fallthrough to next branch - } - // eslint-disable-next-line-no-fallthrough +function isAlreadyFailedLegacyErrorBoundary(instance) { + return ( + legacyErrorBoundariesThatAlreadyFailed !== null && + legacyErrorBoundariesThatAlreadyFailed.has(instance) + ); +} +function markLegacyErrorBoundaryAsFailed(instance) { + if (legacyErrorBoundariesThatAlreadyFailed === null) { + legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); + } else { + legacyErrorBoundariesThatAlreadyFailed.add(instance); + } +} - default: { - recursivelyTraverseReconnectPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions, - includeWorkInProgressEffects - ); - break; - } +function prepareToThrowUncaughtError(error) { + if (!hasUncaughtError) { + hasUncaughtError = true; + firstUncaughtError = error; } } -function recursivelyTraverseAtomicPassiveEffects( - finishedRoot, - parentFiber, - committedLanes, - committedTransitions -) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var prevDebugFiber = getCurrentFiber(); // TODO: Add special flag for atomic effects +var onUncaughtError = prepareToThrowUncaughtError; - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; +function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { + var errorInfo = createCapturedValueAtFiber(error, sourceFiber); + var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane); + var root = enqueueUpdate(rootFiber, update, SyncLane); + var eventTime = requestEventTime(); - while (child !== null) { - setCurrentFiber(child); - commitAtomicPassiveEffects(finishedRoot, child); - child = child.sibling; - } + if (root !== null) { + markRootUpdated(root, SyncLane, eventTime); + ensureRootIsScheduled(root, eventTime); } - - setCurrentFiber(prevDebugFiber); } -function commitAtomicPassiveEffects( - finishedRoot, - finishedWork, - committedLanes, - committedTransitions -) { - // "Atomic" effects are ones that need to fire on every commit, even during - // pre-rendering. We call this function when traversing a hidden tree whose - // regular effects are currently disconnected. - var flags = finishedWork.flags; +function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error$1) { + { + reportUncaughtErrorInDEV(error$1); + setIsRunningInsertionEffect(false); + } - switch (finishedWork.tag) { - case OffscreenComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + if (sourceFiber.tag === HostRoot) { + // Error was thrown at the root. There is no parent, so the root + // itself should capture it. + captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error$1); + return; + } - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var current = finishedWork.alternate; - var instance = finishedWork.stateNode; - commitOffscreenPassiveMountEffects(current, finishedWork, instance); - } + var fiber = null; - break; - } + if (skipUnmountedBoundaries) { + fiber = nearestMountedAncestor; + } else { + fiber = sourceFiber.return; + } - case CacheComponent: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); + while (fiber !== null) { + if (fiber.tag === HostRoot) { + captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error$1); + return; + } else if (fiber.tag === ClassComponent) { + var ctor = fiber.type; + var instance = fiber.stateNode; - if (flags & Passive$1) { - // TODO: Pass `current` as argument to this function - var _current5 = finishedWork.alternate; - commitCachePassiveMountEffect(_current5, finishedWork); - } + if ( + typeof ctor.getDerivedStateFromError === "function" || + (typeof instance.componentDidCatch === "function" && + !isAlreadyFailedLegacyErrorBoundary(instance)) + ) { + var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); + var update = createClassErrorUpdate(fiber, errorInfo, SyncLane); + var root = enqueueUpdate(fiber, update, SyncLane); + var eventTime = requestEventTime(); - break; - } - // eslint-disable-next-line-no-fallthrough + if (root !== null) { + markRootUpdated(root, SyncLane, eventTime); + ensureRootIsScheduled(root, eventTime); + } - default: { - recursivelyTraverseAtomicPassiveEffects(finishedRoot, finishedWork); - break; + return; + } } + + fiber = fiber.return; } -} -function commitPassiveUnmountEffects(finishedWork) { - setCurrentFiber(finishedWork); - commitPassiveUnmountOnFiber(finishedWork); - resetCurrentFiber(); + { + // TODO: Until we re-land skipUnmountedBoundaries (see #20147), this warning + // will fire for errors that are thrown by destroy functions inside deleted + // trees. What it should instead do is propagate the error to the parent of + // the deleted tree. In the meantime, do not add this warning to the + // allowlist; this is only for our internal use. + error( + "Internal React error: Attempted to capture a commit phase error " + + "inside a detached tree. This indicates a bug in React. Likely " + + "causes include deleting the same fiber more than once, committing an " + + "already-finished tree, or an inconsistent return pointer.\n\n" + + "Error message:\n\n%s", + error$1 + ); + } } - -function detachAlternateSiblings(parentFiber) { - // A fiber was deleted from this parent fiber, but it's still part of the - // previous (alternate) parent fiber's list of children. Because children - // are a linked list, an earlier sibling that's still alive will be - // connected to the deleted fiber via its `alternate`: +function attachPingListener(root, wakeable, lanes) { + // Attach a ping listener // - // live fiber --alternate--> previous live fiber --sibling--> deleted - // fiber + // The data might resolve before we have a chance to commit the fallback. Or, + // in the case of a refresh, we'll never commit a fallback. So we need to + // attach a listener now. When it resolves ("pings"), we can decide whether to + // try rendering the tree again. // - // We can't disconnect `alternate` on nodes that haven't been deleted yet, - // but we can disconnect the `sibling` and `child` pointers. - var previousFiber = parentFiber.alternate; + // Only attach a listener if one does not already exist for the lanes + // we're currently rendering (which acts like a "thread ID" here). + // + // We only need to do this in concurrent mode. Legacy Suspense always + // commits fallbacks synchronously, so there are no pings. + var pingCache = root.pingCache; + var threadIDs; - if (previousFiber !== null) { - var detachedChild = previousFiber.child; + if (pingCache === null) { + pingCache = root.pingCache = new PossiblyWeakMap(); + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } else { + threadIDs = pingCache.get(wakeable); - if (detachedChild !== null) { - previousFiber.child = null; + if (threadIDs === undefined) { + threadIDs = new Set(); + pingCache.set(wakeable, threadIDs); + } + } - do { - // $FlowFixMe[incompatible-use] found when upgrading Flow - var detachedSibling = detachedChild.sibling; // $FlowFixMe[incompatible-use] found when upgrading Flow + if (!threadIDs.has(lanes)) { + workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. - detachedChild.sibling = null; - detachedChild = detachedSibling; - } while (detachedChild !== null); + threadIDs.add(lanes); + var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); + + { + if (isDevToolsPresent) { + // If we have pending work still, restore the original updaters + restorePendingUpdaters(root, lanes); + } } - } -} -function commitHookPassiveUnmountEffects( - finishedWork, - nearestMountedAncestor, - hookFlags -) { - if (shouldProfile(finishedWork)) { - startPassiveEffectTimer(); - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); - recordPassiveEffectDuration(finishedWork); - } else { - commitHookEffectListUnmount( - hookFlags, - finishedWork, - nearestMountedAncestor - ); + wakeable.then(ping, ping); } } -function recursivelyTraversePassiveUnmountEffects(parentFiber) { - // Deletions effects can be scheduled on any fiber type. They need to happen - // before the children effects have fired. - var deletions = parentFiber.deletions; +function pingSuspendedRoot(root, wakeable, pingedLanes) { + var pingCache = root.pingCache; - if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; // TODO: Convert this to use recursion + if (pingCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + pingCache.delete(wakeable); + } - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); + var eventTime = requestEventTime(); + markRootPinged(root, pingedLanes); + warnIfSuspenseResolutionNotWrappedWithActDEV(root); + + if ( + workInProgressRoot === root && + isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes) + ) { + // Received a ping at the same priority level at which we're currently + // rendering. We might want to restart this render. This should mirror + // the logic of whether or not a root suspends once it completes. + // TODO: If we're rendering sync either due to Sync, Batched or expired, + // we should probably never restart. + // If we're suspended with delay, or if it's a retry, we'll always suspend + // so we can always restart. + if ( + workInProgressRootExitStatus === RootSuspendedWithDelay || + (workInProgressRootExitStatus === RootSuspended && + includesOnlyRetries(workInProgressRootRenderLanes) && + now$1() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) + ) { + // Force a restart from the root by unwinding the stack. Unless this is + // being called from the render phase, because that would cause a crash. + if ((executionContext & RenderContext) === NoContext) { + prepareFreshStack(root, NoLanes); } + } else { + // Even though we can't restart right now, we might get an + // opportunity later. So we mark this render as having a ping. + workInProgressRootPingedLanes = mergeLanes( + workInProgressRootPingedLanes, + pingedLanes + ); } - - detachAlternateSiblings(parentFiber); } - var prevDebugFiber = getCurrentFiber(); // TODO: Split PassiveMask into separate masks for mount and unmount? + ensureRootIsScheduled(root, eventTime); +} - if (parentFiber.subtreeFlags & PassiveMask) { - var child = parentFiber.child; +function retryTimedOutBoundary(boundaryFiber, retryLane) { + // The boundary fiber (a Suspense component or SuspenseList component) + // previously 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 rendering again, at a new lanes. + if (retryLane === NoLane) { + // TODO: Assign this to `suspenseState.retryLane`? to avoid + // unnecessary entanglement? + retryLane = requestRetryLane(boundaryFiber); + } // TODO: Special case idle priority? - while (child !== null) { - setCurrentFiber(child); - commitPassiveUnmountOnFiber(child); - child = child.sibling; - } - } + var eventTime = requestEventTime(); + var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); - setCurrentFiber(prevDebugFiber); + if (root !== null) { + markRootUpdated(root, retryLane, eventTime); + ensureRootIsScheduled(root, eventTime); + } } -function commitPassiveUnmountOnFiber(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - recursivelyTraversePassiveUnmountEffects(finishedWork); +function retryDehydratedSuspenseBoundary(boundaryFiber) { + var suspenseState = boundaryFiber.memoizedState; + var retryLane = NoLane; - if (finishedWork.flags & Passive$1) { - commitHookPassiveUnmountEffects( - finishedWork, - finishedWork.return, - Passive | HasEffect - ); - } + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; + } - break; - } + retryTimedOutBoundary(boundaryFiber, retryLane); +} +function resolveRetryWakeable(boundaryFiber, wakeable) { + var retryLane = NoLane; // Default - case OffscreenComponent: { - var instance = finishedWork.stateNode; - var nextState = finishedWork.memoizedState; - var isHidden = nextState !== null; + var retryCache; - if ( - isHidden && - instance._visibility & OffscreenPassiveEffectsConnected && // For backwards compatibility, don't unmount when a tree suspends. In - // the future we may change this to unmount after a delay. - (finishedWork.return === null || - finishedWork.return.tag !== SuspenseComponent) - ) { - // The effects are currently connected. Disconnect them. - // TODO: Add option or heuristic to delay before disconnecting the - // effects. Then if the tree reappears before the delay has elapsed, we - // can skip toggling the effects entirely. - instance._visibility &= ~OffscreenPassiveEffectsConnected; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - } else { - recursivelyTraversePassiveUnmountEffects(finishedWork); + switch (boundaryFiber.tag) { + case SuspenseComponent: + retryCache = boundaryFiber.stateNode; + var suspenseState = boundaryFiber.memoizedState; + + if (suspenseState !== null) { + retryLane = suspenseState.retryLane; } break; - } - default: { - recursivelyTraversePassiveUnmountEffects(finishedWork); + case SuspenseListComponent: + retryCache = boundaryFiber.stateNode; + break; + + case OffscreenComponent: { + var instance = boundaryFiber.stateNode; + retryCache = instance._retryCache; break; } + + default: + throw new Error( + "Pinged unknown suspense boundary type. " + + "This is probably a bug in React." + ); } -} -function recursivelyTraverseDisconnectPassiveEffects(parentFiber) { - // Deletions effects can be scheduled on any fiber type. They need to happen - // before the children effects have fired. - var deletions = parentFiber.deletions; + if (retryCache !== null) { + // The wakeable resolved, so we no longer need to memoize, because it will + // never be thrown again. + retryCache.delete(wakeable); + } - if ((parentFiber.flags & ChildDeletion) !== NoFlags$1) { - if (deletions !== null) { - for (var i = 0; i < deletions.length; i++) { - var childToDelete = deletions[i]; // TODO: Convert this to use recursion + retryTimedOutBoundary(boundaryFiber, retryLane); +} // Computes the next Just Noticeable Difference (JND) boundary. +// The theory is that a person can't tell the difference between small differences in time. +// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable +// difference in the experience. However, waiting for longer might mean that we can avoid +// showing an intermediate loading state. The longer we have already waited, the harder it +// is to tell small differences in time. Therefore, the longer we've already waited, +// the longer we can wait additionally. At some point we have to give up though. +// We pick a train model where the next boundary commits at a consistent schedule. +// These particular numbers are vague estimates. We expect to adjust them based on research. - nextEffect = childToDelete; - commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - childToDelete, - parentFiber - ); - } - } +function jnd(timeElapsed) { + return timeElapsed < 120 + ? 120 + : timeElapsed < 480 + ? 480 + : timeElapsed < 1080 + ? 1080 + : timeElapsed < 1920 + ? 1920 + : timeElapsed < 3000 + ? 3000 + : timeElapsed < 4320 + ? 4320 + : ceil(timeElapsed / 1960) * 1960; +} - detachAlternateSiblings(parentFiber); +function throwIfInfiniteUpdateLoopDetected() { + if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { + nestedUpdateCount = 0; + nestedPassiveUpdateCount = 0; + rootWithNestedUpdates = null; + rootWithPassiveNestedUpdates = null; + throw new Error( + "Maximum update depth exceeded. This can happen when a component " + + "repeatedly calls setState inside componentWillUpdate or " + + "componentDidUpdate. React limits the number of nested updates to " + + "prevent infinite loops." + ); } - var prevDebugFiber = getCurrentFiber(); // TODO: Check PassiveStatic flag - - var child = parentFiber.child; + { + if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { + nestedPassiveUpdateCount = 0; + rootWithPassiveNestedUpdates = null; - while (child !== null) { - setCurrentFiber(child); - disconnectPassiveEffect(child); - child = child.sibling; + error( + "Maximum update depth exceeded. This can happen when a component " + + "calls setState inside useEffect, but useEffect either doesn't " + + "have a dependency array, or one of the dependencies changes on " + + "every render." + ); + } } - - setCurrentFiber(prevDebugFiber); } -function disconnectPassiveEffect(finishedWork) { - switch (finishedWork.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - // TODO: Check PassiveStatic flag - commitHookPassiveUnmountEffects( - finishedWork, - finishedWork.return, - Passive - ); // When disconnecting passive effects, we fire the effects in the same - // order as during a deletiong: parent before child +function flushRenderPhaseStrictModeWarningsInDEV() { + { + ReactStrictModeWarnings.flushLegacyContextWarning(); + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); + } +} - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; +function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { + { + { + legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); } + } +} - case OffscreenComponent: { - var instance = finishedWork.stateNode; - - if (instance._visibility & OffscreenPassiveEffectsConnected) { - instance._visibility &= ~OffscreenPassiveEffectsConnected; - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - } +function legacyCommitDoubleInvokeEffectsInDEV(fiber, hasPassiveEffects) { + // TODO (StrictEffects) Should we set a marker on the root if it contains strict effects + // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level. + // Maybe not a big deal since this is DEV only behavior. + setCurrentFiber(fiber); + invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV); - break; - } + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV); + } - default: { - recursivelyTraverseDisconnectPassiveEffects(finishedWork); - break; - } + invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); + + if (hasPassiveEffects) { + invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); } + + resetCurrentFiber(); } -function commitPassiveUnmountEffectsInsideOfDeletedTree_begin( - deletedSubtreeRoot, - nearestMountedAncestor -) { - while (nextEffect !== null) { - var fiber = nextEffect; // Deletion effects fire in parent -> child order - // TODO: Check if fiber has a PassiveStatic flag +function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { + var current = firstChild; + var subtreeRoot = null; - setCurrentFiber(fiber); - commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); - resetCurrentFiber(); - var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. + while (current != null) { + var primarySubtreeFlag = current.subtreeFlags & fiberFlags; - if (child !== null) { - child.return = fiber; - nextEffect = child; + if ( + current !== subtreeRoot && + current.child != null && + primarySubtreeFlag !== NoFlags$1 + ) { + current = current.child; } else { - commitPassiveUnmountEffectsInsideOfDeletedTree_complete( - deletedSubtreeRoot - ); + if ((current.flags & fiberFlags) !== NoFlags$1) { + invokeEffectFn(current); + } + + if (current.sibling !== null) { + current = current.sibling; + } else { + current = subtreeRoot = current.return; + } } } } -function commitPassiveUnmountEffectsInsideOfDeletedTree_complete( - deletedSubtreeRoot -) { - while (nextEffect !== null) { - var fiber = nextEffect; - var sibling = fiber.sibling; - var returnFiber = fiber.return; // Recursively traverse the entire deleted tree and clean up fiber fields. - // This is more aggressive than ideal, and the long term goal is to only - // have to detach the deleted tree at the root. - - detachFiberAfterEffects(fiber); +var didWarnStateUpdateForNotYetMountedComponent = null; +function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { + { + if ((executionContext & RenderContext) !== NoContext) { + // We let the other warning about render phase updates deal with this one. + return; + } - if (fiber === deletedSubtreeRoot) { - nextEffect = null; + if (!(fiber.mode & ConcurrentMode)) { return; } - if (sibling !== null) { - sibling.return = returnFiber; - nextEffect = sibling; + var tag = fiber.tag; + + if ( + tag !== IndeterminateComponent && + tag !== HostRoot && + tag !== ClassComponent && + tag !== FunctionComponent && + tag !== ForwardRef && + tag !== MemoComponent && + tag !== SimpleMemoComponent + ) { + // Only warn for user-defined components, not internal ones like Suspense. return; + } // We show the whole stack but dedupe on the top component's name because + // the problematic code almost always lies inside that component. + + var componentName = getComponentNameFromFiber(fiber) || "ReactComponent"; + + if (didWarnStateUpdateForNotYetMountedComponent !== null) { + if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { + return; + } // $FlowFixMe[incompatible-use] found when upgrading Flow + + didWarnStateUpdateForNotYetMountedComponent.add(componentName); + } else { + didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); } - nextEffect = returnFiber; + var previousFiber = current; + + try { + setCurrentFiber(fiber); + + error( + "Can't perform a React state update on a component that hasn't mounted yet. " + + "This indicates that you have a side-effect in your render function that " + + "asynchronously later calls tries to update the component. Move this work to " + + "useEffect instead." + ); + } finally { + if (previousFiber) { + setCurrentFiber(fiber); + } else { + resetCurrentFiber(); + } + } } } +var beginWork; -function commitPassiveUnmountInsideDeletedTreeOnFiber( - current, - nearestMountedAncestor -) { - switch (current.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - commitHookPassiveUnmountEffects(current, nearestMountedAncestor, Passive); - break; - } - // TODO: run passive unmount effects when unmounting a root. - // Because passive unmount effects are not currently run, - // the cache instance owned by the root will never be freed. - // When effects are run, the cache should be freed here: - // case HostRoot: { - // if (enableCache) { - // const cache = current.memoizedState.cache; - // releaseCache(cache); - // } - // break; - // } +if (replayFailedUnitOfWorkWithInvokeGuardedCallback) { + var dummyFiber = null; - case LegacyHiddenComponent: - case OffscreenComponent: { - { - if ( - current.memoizedState !== null && - current.memoizedState.cachePool !== null - ) { - var cache = current.memoizedState.cachePool.pool; // Retain/release the cache used for pending (suspended) nodes. - // Note that this is only reached in the non-suspended/visible case: - // when the content is suspended/hidden, the retain/release occurs - // via the parent Suspense component (see case above). + beginWork = function (current, unitOfWork, lanes) { + // If a component throws an error, we replay it again in a synchronously + // dispatched event, so that the debugger will treat it as an uncaught + // error See ReactErrorUtils for more information. + // Before entering the begin phase, copy the work-in-progress onto a dummy + // fiber. If beginWork throws, we'll use this to reset the state. + var originalWorkInProgressCopy = assignFiberPropertiesInDEV( + dummyFiber, + unitOfWork + ); - if (cache != null) { - retainCache(cache); - } - } - } + try { + return beginWork$1(current, unitOfWork, lanes); + } catch (originalError) { + if ( + didSuspendOrErrorWhileHydratingDEV() || + originalError === SuspenseException || + originalError === SelectiveHydrationException || + (originalError !== null && + typeof originalError === "object" && + typeof originalError.then === "function") + ) { + // Don't replay promises. + // Don't replay errors if we are hydrating and have already suspended or handled an error + throw originalError; + } // Don't reset current debug fiber, since we're about to work on the + // same fiber again. + // Unwind the failed stack frame - break; - } + resetSuspendedWorkLoopOnUnwind(); + unwindInterruptedWork(current, unitOfWork); // Restore the original properties of the fiber. - case SuspenseComponent: { - if (enableTransitionTracing) { - // We need to mark this fiber's parents as deleted - var offscreenFiber = current.child; - var instance = offscreenFiber.stateNode; - var transitions = instance._transitions; + assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); - if (transitions !== null) { - var abortReason = { - reason: "suspense", - name: current.memoizedProps.unstable_name || null - }; + if (unitOfWork.mode & ProfileMode) { + // Reset the profiler timer. + startProfilerTimer(unitOfWork); + } // Run beginWork again. - if ( - current.memoizedState === null || - current.memoizedState.dehydrated === null - ) { - abortParentMarkerTransitionsForDeletedFiber( - offscreenFiber, - abortReason, - transitions, - instance, - true - ); + invokeGuardedCallback( + null, + beginWork$1, + null, + current, + unitOfWork, + lanes + ); - if (nearestMountedAncestor !== null) { - abortParentMarkerTransitionsForDeletedFiber( - nearestMountedAncestor, - abortReason, - transitions, - instance, - false - ); - } - } + if (hasCaughtError()) { + var replayError = clearCaughtError(); + + if ( + typeof replayError === "object" && + replayError !== null && + replayError._suppressLogging && + typeof originalError === "object" && + originalError !== null && + !originalError._suppressLogging + ) { + // If suppressed, let the flag carry over to the original error which is the one we'll rethrow. + originalError._suppressLogging = true; } - } + } // We always throw the original error in case the second render pass is not idempotent. + // This can happen if a memoized function or CommonJS module doesn't throw after first invocation. - break; + throw originalError; } + }; +} else { + beginWork = beginWork$1; +} - case CacheComponent: { - { - var _cache = current.memoizedState.cache; - releaseCache(_cache); - } +var didWarnAboutUpdateInRender = false; +var didWarnAboutUpdateInRenderForAnotherComponent; - break; - } +{ + didWarnAboutUpdateInRenderForAnotherComponent = new Set(); +} - case TracingMarkerComponent: { - if (enableTransitionTracing) { - // We need to mark this fiber's parents as deleted - var _instance5 = current.stateNode; - var _transitions = _instance5.transitions; +function warnAboutRenderPhaseUpdatesInDEV(fiber) { + { + if (isRendering) { + switch (fiber.tag) { + case FunctionComponent: + case ForwardRef: + case SimpleMemoComponent: { + var renderingComponentName = + (workInProgress && getComponentNameFromFiber(workInProgress)) || + "Unknown"; // Dedupe by the rendering component because it's the one that needs to be fixed. - if (_transitions !== null) { - var _abortReason = { - reason: "marker", - name: current.memoizedProps.name - }; - abortParentMarkerTransitionsForDeletedFiber( - current, - _abortReason, - _transitions, - null, - true - ); + var dedupeKey = renderingComponentName; - if (nearestMountedAncestor !== null) { - abortParentMarkerTransitionsForDeletedFiber( - nearestMountedAncestor, - _abortReason, - _transitions, - null, - false + if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { + didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); + var setStateComponentName = + getComponentNameFromFiber(fiber) || "Unknown"; + + error( + "Cannot update a component (`%s`) while rendering a " + + "different component (`%s`). To locate the bad setState() call inside `%s`, " + + "follow the stack trace as described in https://reactjs.org/link/setstate-in-render", + setStateComponentName, + renderingComponentName, + renderingComponentName ); } - } - } - - break; - } - } -} -function invokeLayoutEffectMountInDEV(fiber) { - { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - try { - commitHookEffectListMount(Layout | HasEffect, fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); + break; } - break; - } + case ClassComponent: { + if (!didWarnAboutUpdateInRender) { + error( + "Cannot update during an existing state transition (such as " + + "within `render`). Render methods should be a pure " + + "function of props and state." + ); - case ClassComponent: { - var instance = fiber.stateNode; + didWarnAboutUpdateInRender = true; + } - try { - instance.componentDidMount(); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); + break; } - - break; } } } } -function invokePassiveEffectMountInDEV(fiber) { +function restorePendingUpdaters(root, lanes) { { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - try { - commitHookEffectListMount(Passive | HasEffect, fiber); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - - break; - } + if (isDevToolsPresent) { + var memoizedUpdaters = root.memoizedUpdaters; + memoizedUpdaters.forEach(function (schedulingFiber) { + addFiberToLanesMap(root, schedulingFiber, lanes); + }); // This function intentionally does not clear memoized updaters. + // Those may still be relevant to the current commit + // and a future one (e.g. Suspense). } } } +var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] -function invokeLayoutEffectUnmountInDEV(fiber) { +function scheduleCallback(priorityLevel, callback) { { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - try { - commitHookEffectListUnmount(Layout | HasEffect, fiber, fiber.return); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - - break; - } - - case ClassComponent: { - var instance = fiber.stateNode; - - if (typeof instance.componentWillUnmount === "function") { - safelyCallComponentWillUnmount(fiber, fiber.return, instance); - } + // If we're currently inside an `act` scope, bypass Scheduler and push to + // the `act` queue instead. + var actQueue = ReactCurrentActQueue.current; - break; - } + if (actQueue !== null) { + actQueue.push(callback); + return fakeActCallbackNode; + } else { + return scheduleCallback$2(priorityLevel, callback); } } } -function invokePassiveEffectUnmountInDEV(fiber) { - { - // We don't need to re-check StrictEffectsMode here. - // This function is only called if that check has already passed. - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - try { - commitHookEffectListUnmount(Passive | HasEffect, fiber, fiber.return); - } catch (error) { - captureCommitPhaseError(fiber, fiber.return, error); - } - } - } - } +function cancelCallback(callbackNode) { + if (callbackNode === fakeActCallbackNode) { + return; + } // In production, always call Scheduler. This function will be stripped out. + + return cancelCallback$1(callbackNode); } -function getCacheSignal() { - var cache = readContext(CacheContext); - return cache.controller.signal; +function shouldForceFlushFallbacksInDEV() { + // Never force flush in production. This function should get stripped out. + return ReactCurrentActQueue.current !== null; } -function getCacheForType(resourceType) { - var cache = readContext(CacheContext); - var cacheForType = cache.data.get(resourceType); +function warnIfUpdatesNotWrappedWithActDEV(fiber) { + { + if (fiber.mode & ConcurrentMode) { + if (!isConcurrentActEnvironment()) { + // Not in an act environment. No need to warn. + return; + } + } else { + // Legacy mode has additional cases where we suppress a warning. + if (!isLegacyActEnvironment()) { + // Not in an act environment. No need to warn. + return; + } - if (cacheForType === undefined) { - cacheForType = resourceType(); - cache.data.set(resourceType, cacheForType); - } + if (executionContext !== NoContext) { + // Legacy mode doesn't warn if the update is batched, i.e. + // batchedUpdates or flushSync. + return; + } - return cacheForType; -} + if ( + fiber.tag !== FunctionComponent && + fiber.tag !== ForwardRef && + fiber.tag !== SimpleMemoComponent + ) { + // For backwards compatibility with pre-hooks code, legacy mode only + // warns for updates that originate from a hook. + return; + } + } -var DefaultCacheDispatcher = { - getCacheSignal: getCacheSignal, - getCacheForType: getCacheForType -}; + if (ReactCurrentActQueue.current === null) { + var previousFiber = current; -if (typeof Symbol === "function" && Symbol.for) { - var symbolFor = Symbol.for; - symbolFor("selector.component"); - symbolFor("selector.has_pseudo_class"); - symbolFor("selector.role"); - symbolFor("selector.test_id"); - symbolFor("selector.text"); -} -var commitHooks = []; -function onCommitRoot() { - { - commitHooks.forEach(function (commitHook) { - return commitHook(); - }); + try { + setCurrentFiber(fiber); + + error( + "An update to %s inside a test was not wrapped in act(...).\n\n" + + "When testing, code that causes React state updates should be " + + "wrapped into act(...):\n\n" + + "act(() => {\n" + + " /* fire events that update state */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://reactjs.org/link/wrap-tests-with-act", + getComponentNameFromFiber(fiber) + ); + } finally { + if (previousFiber) { + setCurrentFiber(fiber); + } else { + resetCurrentFiber(); + } + } + } } } -var ReactCurrentActQueue$1 = ReactSharedInternals.ReactCurrentActQueue; -function isLegacyActEnvironment(fiber) { - { - // Legacy mode. We preserve the behavior of React 17's act. It assumes an - // act environment whenever `jest` is defined, but you can still turn off - // spurious warnings by setting IS_REACT_ACT_ENVIRONMENT explicitly - // to false. - var isReactActEnvironmentGlobal = // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global - typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] - ? IS_REACT_ACT_ENVIRONMENT - : undefined; // $FlowFixMe - Flow doesn't know about jest - - var jestIsDefined = typeof jest !== "undefined"; - return jestIsDefined && isReactActEnvironmentGlobal !== false; - } -} -function isConcurrentActEnvironment() { +function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { { - var isReactActEnvironmentGlobal = // $FlowFixMe[cannot-resolve-name] Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global - typeof IS_REACT_ACT_ENVIRONMENT !== "undefined" // $FlowFixMe[cannot-resolve-name] - ? IS_REACT_ACT_ENVIRONMENT - : undefined; - if ( - !isReactActEnvironmentGlobal && - ReactCurrentActQueue$1.current !== null + root.tag !== LegacyRoot && + isConcurrentActEnvironment() && + ReactCurrentActQueue.current === null ) { - // TODO: Include link to relevant documentation page. error( - "The current testing environment is not configured to support " + - "act(...)" + "A suspended resource finished loading inside a test, but the event " + + "was not wrapped in act(...).\n\n" + + "When testing, code that resolves suspended data should be wrapped " + + "into act(...):\n\n" + + "act(() => {\n" + + " /* finish loading suspended data */\n" + + "});\n" + + "/* assert on the output */\n\n" + + "This ensures that you're testing the behavior the user would see " + + "in the browser." + + " Learn more at https://reactjs.org/link/wrap-tests-with-act" ); } - - return isReactActEnvironmentGlobal; } } -var postPaintCallbackScheduled = false; -var callbacks = []; -function schedulePostPaintCallback(callback) { - callbacks.push(callback); +function setIsRunningInsertionEffect(isRunning) { + { + isRunningInsertionEffect = isRunning; + } +} - if (!postPaintCallbackScheduled) { - postPaintCallbackScheduled = true; - requestPostPaintCallback(function (endTime) { - for (var i = 0; i < callbacks.length; i++) { - callbacks[i](endTime); - } +/* eslint-disable react-internal/prod-error-codes */ +// Used by React Refresh runtime through DevTools Global Hook. - postPaintCallbackScheduled = false; - callbacks = []; - }); +var resolveFamily = null; +var failedBoundaries = null; +var setRefreshHandler = function (handler) { + { + resolveFamily = handler; } -} +}; +function resolveFunctionForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; + } -var ceil = Math.ceil; -var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; -var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher, - ReactCurrentCache = ReactSharedInternals.ReactCurrentCache, - ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner, - ReactCurrentBatchConfig = ReactSharedInternals.ReactCurrentBatchConfig, - ReactCurrentActQueue = ReactSharedInternals.ReactCurrentActQueue; -var NoContext = - /* */ - 0; -var BatchedContext = - /* */ - 1; -var RenderContext = - /* */ - 2; -var CommitContext = - /* */ - 4; -var RootInProgress = 0; -var RootFatalErrored = 1; -var RootErrored = 2; -var RootSuspended = 3; -var RootSuspendedWithDelay = 4; -var RootCompleted = 5; -var RootDidNotComplete = 6; // Describes where we are in the React execution stack + var family = resolveFamily(type); -var executionContext = NoContext; // The root we're working on + if (family === undefined) { + return type; + } // Use the latest known implementation. -var workInProgressRoot = null; // The fiber we're working on + return family.current; + } +} +function resolveClassForHotReloading(type) { + // No implementation differences. + return resolveFunctionForHotReloading(type); +} +function resolveForwardRefForHotReloading(type) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return type; + } -var workInProgress = null; // The lanes we're rendering + var family = resolveFamily(type); -var workInProgressRootRenderLanes = NoLanes; -var NotSuspended = 0; -var SuspendedOnError = 1; -var SuspendedOnData = 2; -var SuspendedOnImmediate = 3; -var SuspendedOnDeprecatedThrowPromise = 4; -var SuspendedAndReadyToContinue = 5; -var SuspendedOnHydration = 6; // When this is true, the work-in-progress fiber just suspended (or errored) and -// we've yet to unwind the stack. In some cases, we may yield to the main thread -// after this happens. If the fiber is pinged before we resume, we can retry -// immediately instead of unwinding the stack. + if (family === undefined) { + // Check if we're dealing with a real forwardRef. Don't want to crash early. + if ( + type !== null && + type !== undefined && + typeof type.render === "function" + ) { + // ForwardRef is special because its resolved .type is an object, + // but it's possible that we only have its inner render function in the map. + // If that inner render function is different, we'll build a new forwardRef type. + var currentRender = resolveFunctionForHotReloading(type.render); -var workInProgressSuspendedReason = NotSuspended; -var workInProgressThrownValue = null; // Whether a ping listener was attached during this render. This is slightly -// different that whether something suspended, because we don't add multiple -// listeners to a promise we've already seen (per root and lane). + if (type.render !== currentRender) { + var syntheticType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render: currentRender + }; -var workInProgressRootDidAttachPingListener = false; // A contextual version of workInProgressRootRenderLanes. It is a superset of -// the lanes that we started working on at the root. When we enter a subtree -// that is currently hidden, we add the lanes that would have committed if -// the hidden tree hadn't been deferred. This is modified by the -// HiddenContext module. -// -// Most things in the work loop should deal with workInProgressRootRenderLanes. -// Most things in begin/complete phases should deal with renderLanes. + if (type.displayName !== undefined) { + syntheticType.displayName = type.displayName; + } -var renderLanes = NoLanes; // Whether to root completed, errored, suspended, etc. + return syntheticType; + } + } -var workInProgressRootExitStatus = RootInProgress; // A fatal error, if one is thrown + return type; + } // Use the latest known implementation. -var workInProgressRootFatalError = null; // The work left over by components that were visited during this render. Only -// includes unprocessed updates, not work in bailed out children. + return family.current; + } +} +function isCompatibleFamilyForHotReloading(fiber, element) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return false; + } -var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render. + var prevType = fiber.elementType; + var nextType = element.type; // If we got here, we know types aren't === equal. -var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event). + var needsCompareFamilies = false; + var $$typeofNextType = + typeof nextType === "object" && nextType !== null + ? nextType.$$typeof + : null; -var workInProgressRootPingedLanes = NoLanes; // Errors that are thrown during the render phase. + switch (fiber.tag) { + case ClassComponent: { + if (typeof nextType === "function") { + needsCompareFamilies = true; + } -var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI. -// We will log them once the tree commits. + break; + } -var workInProgressRootRecoverableErrors = null; // The most recent time we committed a fallback. This lets us ensure a train -// model where we don't commit new loading states in too quick succession. + case FunctionComponent: { + if (typeof nextType === "function") { + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + // We don't know the inner type yet. + // We're going to assume that the lazy inner type is stable, + // and so it is sufficient to avoid reconciling it away. + // We're not going to unwrap or actually use the new lazy type. + needsCompareFamilies = true; + } -var globalMostRecentFallbackTime = 0; -var FALLBACK_THROTTLE_MS = 500; // The absolute time for when we should start giving up on rendering -// more and prefer CPU suspense heuristics instead. + break; + } -var workInProgressRootRenderTargetTime = Infinity; // How long a render is supposed to take before we start following CPU -// suspense heuristics and opt out of rendering more content. + case ForwardRef: { + if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + needsCompareFamilies = true; + } -var RENDER_TIMEOUT_MS = 500; -var workInProgressTransitions = null; -function getWorkInProgressTransitions() { - return workInProgressTransitions; -} -var currentPendingTransitionCallbacks = null; -var currentEndTime = null; -function addTransitionStartCallbackToPendingTransition(transition) { - if (enableTransitionTracing) { - if (currentPendingTransitionCallbacks === null) { - currentPendingTransitionCallbacks = { - transitionStart: [], - transitionProgress: null, - transitionComplete: null, - markerProgress: null, - markerIncomplete: null, - markerComplete: null - }; - } + break; + } - if (currentPendingTransitionCallbacks.transitionStart === null) { - currentPendingTransitionCallbacks.transitionStart = []; - } + case MemoComponent: + case SimpleMemoComponent: { + if ($$typeofNextType === REACT_MEMO_TYPE) { + // TODO: if it was but can no longer be simple, + // we shouldn't set this. + needsCompareFamilies = true; + } else if ($$typeofNextType === REACT_LAZY_TYPE) { + needsCompareFamilies = true; + } - currentPendingTransitionCallbacks.transitionStart.push(transition); - } -} -function addMarkerProgressCallbackToPendingTransition( - markerName, - transitions, - pendingBoundaries -) { - if (enableTransitionTracing) { - if (currentPendingTransitionCallbacks === null) { - currentPendingTransitionCallbacks = { - transitionStart: null, - transitionProgress: null, - transitionComplete: null, - markerProgress: new Map(), - markerIncomplete: null, - markerComplete: null - }; - } + break; + } - if (currentPendingTransitionCallbacks.markerProgress === null) { - currentPendingTransitionCallbacks.markerProgress = new Map(); - } + default: + return false; + } // Check if both types have a family and it's the same one. - currentPendingTransitionCallbacks.markerProgress.set(markerName, { - pendingBoundaries: pendingBoundaries, - transitions: transitions - }); - } -} -function addMarkerIncompleteCallbackToPendingTransition( - markerName, - transitions, - aborts -) { - if (enableTransitionTracing) { - if (currentPendingTransitionCallbacks === null) { - currentPendingTransitionCallbacks = { - transitionStart: null, - transitionProgress: null, - transitionComplete: null, - markerProgress: null, - markerIncomplete: new Map(), - markerComplete: null - }; - } + if (needsCompareFamilies) { + // Note: memo() and forwardRef() we'll compare outer rather than inner type. + // This means both of them need to be registered to preserve state. + // If we unwrapped and compared the inner types for wrappers instead, + // then we would risk falsely saying two separate memo(Foo) + // calls are equivalent because they wrap the same Foo function. + var prevFamily = resolveFamily(prevType); // $FlowFixMe[not-a-function] found when upgrading Flow - if (currentPendingTransitionCallbacks.markerIncomplete === null) { - currentPendingTransitionCallbacks.markerIncomplete = new Map(); + if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { + return true; + } } - currentPendingTransitionCallbacks.markerIncomplete.set(markerName, { - transitions: transitions, - aborts: aborts - }); + return false; } } -function addMarkerCompleteCallbackToPendingTransition(markerName, transitions) { - if (enableTransitionTracing) { - if (currentPendingTransitionCallbacks === null) { - currentPendingTransitionCallbacks = { - transitionStart: null, - transitionProgress: null, - transitionComplete: null, - markerProgress: null, - markerIncomplete: null, - markerComplete: new Map() - }; - } - - if (currentPendingTransitionCallbacks.markerComplete === null) { - currentPendingTransitionCallbacks.markerComplete = new Map(); +function markFailedErrorBoundaryForHotReloading(fiber) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; } - currentPendingTransitionCallbacks.markerComplete.set( - markerName, - transitions - ); - } -} -function addTransitionProgressCallbackToPendingTransition( - transition, - boundaries -) { - if (enableTransitionTracing) { - if (currentPendingTransitionCallbacks === null) { - currentPendingTransitionCallbacks = { - transitionStart: null, - transitionProgress: new Map(), - transitionComplete: null, - markerProgress: null, - markerIncomplete: null, - markerComplete: null - }; + if (typeof WeakSet !== "function") { + return; } - if (currentPendingTransitionCallbacks.transitionProgress === null) { - currentPendingTransitionCallbacks.transitionProgress = new Map(); + if (failedBoundaries === null) { + failedBoundaries = new WeakSet(); } - currentPendingTransitionCallbacks.transitionProgress.set( - transition, - boundaries - ); + failedBoundaries.add(fiber); } } -function addTransitionCompleteCallbackToPendingTransition(transition) { - if (enableTransitionTracing) { - if (currentPendingTransitionCallbacks === null) { - currentPendingTransitionCallbacks = { - transitionStart: null, - transitionProgress: null, - transitionComplete: [], - markerProgress: null, - markerIncomplete: null, - markerComplete: null - }; +var scheduleRefresh = function (root, update) { + { + if (resolveFamily === null) { + // Hot reloading is disabled. + return; } - if (currentPendingTransitionCallbacks.transitionComplete === null) { - currentPendingTransitionCallbacks.transitionComplete = []; + var staleFamilies = update.staleFamilies, + updatedFamilies = update.updatedFamilies; + flushPassiveEffects(); + flushSync$1(function () { + scheduleFibersWithFamiliesRecursively( + root.current, + updatedFamilies, + staleFamilies + ); + }); + } +}; +var scheduleRoot = function (root, element) { + { + if (root.context !== emptyContextObject) { + // Super edge case: root has a legacy _renderSubtree context + // but we don't know the parentComponent so we can't pass it. + // Just ignore. We'll delete this with _renderSubtree code path later. + return; } - currentPendingTransitionCallbacks.transitionComplete.push(transition); + flushPassiveEffects(); + flushSync$1(function () { + updateContainer(element, root, null, null); + }); } -} - -function resetRenderTimer() { - workInProgressRootRenderTargetTime = now$1() + RENDER_TIMEOUT_MS; -} - -function getRenderTargetTime() { - return workInProgressRootRenderTargetTime; -} -var hasUncaughtError = false; -var firstUncaughtError = null; -var legacyErrorBoundariesThatAlreadyFailed = null; // Only used when enableProfilerNestedUpdateScheduledHook is true; -// to track which root is currently committing layout effects. - -var rootCommittingMutationOrLayoutEffects = null; -var rootDoesHavePassiveEffects = false; -var rootWithPendingPassiveEffects = null; -var pendingPassiveEffectsLanes = NoLanes; -var pendingPassiveProfilerEffects = []; -var pendingPassiveEffectsRemainingLanes = NoLanes; -var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates - -var NESTED_UPDATE_LIMIT = 50; -var nestedUpdateCount = 0; -var rootWithNestedUpdates = null; -var isFlushingPassiveEffects = false; -var didScheduleUpdateDuringPassiveEffects = false; -var NESTED_PASSIVE_UPDATE_LIMIT = 50; -var nestedPassiveUpdateCount = 0; -var rootWithPassiveNestedUpdates = null; // If two updates are scheduled within the same event, we should treat their -// event times as simultaneous, even if the actual clock time has advanced -// between the first and second call. - -var currentEventTime = NoTimestamp; -var currentEventTransitionLane = NoLanes; -var isRunningInsertionEffect = false; -function getWorkInProgressRoot() { - return workInProgressRoot; -} -function getWorkInProgressRootRenderLanes() { - return workInProgressRootRenderLanes; -} -function requestEventTime() { - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - // We're inside React, so it's fine to read the actual time. - return now$1(); - } // We're not inside React, so we may be in the middle of a browser event. - - if (currentEventTime !== NoTimestamp) { - // Use the same start time for all updates until we enter React again. - return currentEventTime; - } // This is the first update since React yielded. Compute a new start time. - - currentEventTime = now$1(); - return currentEventTime; -} -function requestUpdateLane(fiber) { - // Special cases - var mode = fiber.mode; +}; - if ((mode & ConcurrentMode) === NoMode) { - return SyncLane; - } else if ( - !deferRenderPhaseUpdateToNextBatch && - (executionContext & RenderContext) !== NoContext && - workInProgressRootRenderLanes !== NoLanes - ) { - // This is a render phase update. These are not officially supported. The - // old behavior is to give this the same "thread" (lanes) as - // whatever is currently rendering. So if you call `setState` on a component - // that happens later in the same render, it will flush. Ideally, we want to - // remove the special case and treat them as if they came from an - // interleaved event. Regardless, this pattern is not officially supported. - // This behavior is only a fallback. The flag only exists until we can roll - // out the setState warning, since existing code might accidentally rely on - // the current behavior. - return pickArbitraryLane(workInProgressRootRenderLanes); - } +function scheduleFibersWithFamiliesRecursively( + fiber, + updatedFamilies, + staleFamilies +) { + { + var alternate = fiber.alternate, + child = fiber.child, + sibling = fiber.sibling, + tag = fiber.tag, + type = fiber.type; + var candidateType = null; - var isTransition = requestCurrentTransition() !== NoTransition; + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; - if (isTransition) { - if (ReactCurrentBatchConfig.transition !== null) { - var transition = ReactCurrentBatchConfig.transition; + case ForwardRef: + candidateType = type.render; + break; + } - if (!transition._updatedFibers) { - transition._updatedFibers = new Set(); - } + if (resolveFamily === null) { + throw new Error("Expected resolveFamily to be set during hot reload."); + } - transition._updatedFibers.add(fiber); - } // The algorithm for assigning an update to a lane should be stable for all - // updates at the same priority within the same event. To do this, the - // inputs to the algorithm must be the same. - // - // The trick we use is to cache the first of each of these inputs within an - // event. Then reset the cached values once we can be sure the event is - // over. Our heuristic for that is whenever we enter a concurrent work loop. + var needsRender = false; + var needsRemount = false; - if (currentEventTransitionLane === NoLane) { - // All transitions within the same event are assigned the same lane. - currentEventTransitionLane = claimNextTransitionLane(); + if (candidateType !== null) { + var family = resolveFamily(candidateType); + + if (family !== undefined) { + if (staleFamilies.has(family)) { + needsRemount = true; + } else if (updatedFamilies.has(family)) { + if (tag === ClassComponent) { + needsRemount = true; + } else { + needsRender = true; + } + } + } } - return currentEventTransitionLane; - } // Updates originating inside certain React methods, like flushSync, have - // their priority set by tracking it with a context variable. - // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. - // TODO: Move this type conversion to the event priority module. + if (failedBoundaries !== null) { + if ( + failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow + (alternate !== null && failedBoundaries.has(alternate)) + ) { + needsRemount = true; + } + } - var updateLane = getCurrentUpdatePriority$1(); + if (needsRemount) { + fiber._debugNeedsRemount = true; + } - if (updateLane !== NoLane) { - return updateLane; - } // This update originated outside React. Ask the host environment for an - // appropriate priority, based on the type of event. - // - // The opaque type returned by the host config is internally a lane, so we can - // use that directly. - // TODO: Move this type conversion to the event priority module. + if (needsRemount || needsRender) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - var eventLane = getCurrentEventPriority(); - return eventLane; -} + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + } -function requestRetryLane(fiber) { - // This is a fork of `requestUpdateLane` designed specifically for Suspense - // "retries" — a special update that attempts to flip a Suspense boundary - // from its placeholder state to its primary/resolved state. - // Special cases - var mode = fiber.mode; + if (child !== null && !needsRemount) { + scheduleFibersWithFamiliesRecursively( + child, + updatedFamilies, + staleFamilies + ); + } - if ((mode & ConcurrentMode) === NoMode) { - return SyncLane; + if (sibling !== null) { + scheduleFibersWithFamiliesRecursively( + sibling, + updatedFamilies, + staleFamilies + ); + } } - - return claimNextRetryLane(); } -function scheduleUpdateOnFiber(root, fiber, lane, eventTime) { +var findHostInstancesForRefresh = function (root, families) { { - if (isRunningInsertionEffect) { - error("useInsertionEffect must not schedule updates."); - } + var hostInstances = new Set(); + var types = new Set( + families.map(function (family) { + return family.current; + }) + ); + findHostInstancesForMatchingFibersRecursively( + root.current, + types, + hostInstances + ); + return hostInstances; } +}; +function findHostInstancesForMatchingFibersRecursively( + fiber, + types, + hostInstances +) { { - if (isFlushingPassiveEffects) { - didScheduleUpdateDuringPassiveEffects = true; + var child = fiber.child, + sibling = fiber.sibling, + tag = fiber.tag, + type = fiber.type; + var candidateType = null; + + switch (tag) { + case FunctionComponent: + case SimpleMemoComponent: + case ClassComponent: + candidateType = type; + break; + + case ForwardRef: + candidateType = type.render; + break; } - } // Check if the work loop is currently suspended and waiting for data to - // finish loading. - if ( - workInProgressSuspendedReason === SuspendedOnData && - root === workInProgressRoot - ) { - // The incoming update might unblock the current render. Interrupt the - // current attempt and restart from the top. - prepareFreshStack(root, NoLanes); - markRootSuspended(root, workInProgressRootRenderLanes); - } // Mark that the root has a pending update. + var didMatch = false; - markRootUpdated(root, lane, eventTime); + if (candidateType !== null) { + if (types.has(candidateType)) { + didMatch = true; + } + } - if ( - (executionContext & RenderContext) !== NoLanes && - root === workInProgressRoot - ) { - // This update was dispatched during the render phase. This is a mistake - // if the update originates from user space (with the exception of local - // hook updates, which are handled differently and don't reach this - // function), but there are some internal React features that use this as - // an implementation detail, like selective hydration. - warnAboutRenderPhaseUpdatesInDEV(fiber); // Track lanes that were updated during the render phase - } else { - // This is a normal update, scheduled from outside the render phase. For - // example, during an input event. - { - if (isDevToolsPresent) { - addFiberToLanesMap(root, fiber, lane); + if (didMatch) { + // We have a match. This only drills down to the closest host components. + // There's no need to search deeper because for the purpose of giving + // visual feedback, "flashing" outermost parent rectangles is sufficient. + findHostInstancesForFiberShallowly(fiber, hostInstances); + } else { + // If there's no match, maybe there will be one further down in the child tree. + if (child !== null) { + findHostInstancesForMatchingFibersRecursively( + child, + types, + hostInstances + ); } } - warnIfUpdatesNotWrappedWithActDEV(fiber); + if (sibling !== null) { + findHostInstancesForMatchingFibersRecursively( + sibling, + types, + hostInstances + ); + } + } +} - if (enableProfilerNestedUpdateScheduledHook) { - if ( - (executionContext & CommitContext) !== NoContext && - root === rootCommittingMutationOrLayoutEffects - ) { - if (fiber.mode & ProfileMode) { - var current = fiber; +function findHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var foundHostInstances = findChildHostInstancesForFiberShallowly( + fiber, + hostInstances + ); - while (current !== null) { - if (current.tag === Profiler) { - var _current$memoizedProp = current.memoizedProps, - id = _current$memoizedProp.id, - onNestedUpdateScheduled = - _current$memoizedProp.onNestedUpdateScheduled; + if (foundHostInstances) { + return; + } // If we didn't find any host children, fallback to closest host parent. - if (typeof onNestedUpdateScheduled === "function") { - onNestedUpdateScheduled(id); - } - } + var node = fiber; - current = current.return; - } - } - } - } + while (true) { + switch (node.tag) { + case HostSingleton: + case HostComponent: + hostInstances.add(node.stateNode); + return; - if (enableTransitionTracing) { - var transition = ReactCurrentBatchConfig.transition; + case HostPortal: + hostInstances.add(node.stateNode.containerInfo); + return; - if (transition !== null && transition.name != null) { - if (transition.startTime === -1) { - transition.startTime = now$1(); - } + case HostRoot: + hostInstances.add(node.stateNode.containerInfo); + return; + } - addTransitionToLanesMap(root, transition, lane); + if (node.return === null) { + throw new Error("Expected to reach root first."); } + + node = node.return; } + } +} - if (root === workInProgressRoot) { - // Received an update to a tree that's in the middle of rendering. Mark - // that there was an interleaved update work on this root. Unless the - // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render - // phase update. In that case, we don't treat render phase updates as if - // they were interleaved, for backwards compat reasons. +function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { + { + var node = fiber; + var foundHostInstances = false; + + while (true) { if ( - deferRenderPhaseUpdateToNextBatch || - (executionContext & RenderContext) === NoContext + node.tag === HostComponent || + node.tag === HostHoistable || + node.tag === HostSingleton ) { - workInProgressRootInterleavedUpdatedLanes = mergeLanes( - workInProgressRootInterleavedUpdatedLanes, - lane - ); + // We got a match. + foundHostInstances = true; + hostInstances.add(node.stateNode); // There may still be more, so keep searching. + } else if (node.child !== null) { + node.child.return = node; + node = node.child; + continue; } - if (workInProgressRootExitStatus === RootSuspendedWithDelay) { - // The root already suspended with a delay, which means this render - // definitely won't finish. Since we have a new update, let's mark it as - // suspended now, right before marking the incoming update. This has the - // effect of interrupting the current render and switching to the update. - // TODO: Make sure this doesn't override pings that happen while we've - // already started rendering. - markRootSuspended(root, workInProgressRootRenderLanes); + if (node === fiber) { + return foundHostInstances; } - } - ensureRootIsScheduled(root, eventTime); + while (node.sibling === null) { + if (node.return === null || node.return === fiber) { + return foundHostInstances; + } - if ( - lane === SyncLane && - executionContext === NoContext && - (fiber.mode & ConcurrentMode) === NoMode && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. - !ReactCurrentActQueue.isBatchingLegacy - ) { - // Flush the synchronous work now, unless we're already working or inside - // a batch. This is intentionally inside scheduleUpdateOnFiber instead of - // scheduleCallbackForFiber to preserve the ability to schedule a callback - // without immediately flushing it. We only do this for user-initiated - // updates, to preserve historical behavior of legacy mode. - resetRenderTimer(); - flushSyncCallbacksOnlyInLegacyMode(); + node = node.return; + } + + node.sibling.return = node.return; + node = node.sibling; } } + + return false; } -function scheduleInitialHydrationOnRoot(root, lane, eventTime) { - // This is a special fork of scheduleUpdateOnFiber that is only used to - // schedule the initial hydration of a root that has just been created. Most - // of the stuff in scheduleUpdateOnFiber can be skipped. - // - // The main reason for this separate path, though, is to distinguish the - // initial children from subsequent updates. In fully client-rendered roots - // (createRoot instead of hydrateRoot), all top-level renders are modeled as - // updates, but hydration roots are special because the initial render must - // match what was rendered on the server. - var current = root.current; - current.lanes = lane; - markRootUpdated(root, lane, eventTime); - ensureRootIsScheduled(root, eventTime); + +var hasBadMapPolyfill; + +{ + hasBadMapPolyfill = false; + + try { + var nonExtensibleObject = Object.preventExtensions({}); + /* eslint-disable no-new */ + + new Map([[nonExtensibleObject, null]]); + new Set([nonExtensibleObject]); + /* eslint-enable no-new */ + } catch (e) { + // TODO: Consider warning about bad polyfills + hasBadMapPolyfill = true; + } } -function isUnsafeClassRenderPhaseUpdate(fiber) { - // Check if this is a render phase update. Only called by class components, - // which special (deprecated) behavior for UNSAFE_componentWillReceive props. - return ( - // TODO: Remove outdated deferRenderPhaseUpdateToNextBatch experiment. We - // decided not to enable it. - (!deferRenderPhaseUpdateToNextBatch || - (fiber.mode & ConcurrentMode) === NoMode) && - (executionContext & RenderContext) !== NoContext - ); -} // Use this function to schedule a task for a root. There's only one task per -// root; if a task was already scheduled, we'll check to make sure the priority -// of the existing task is the same as the priority of the next level that the -// root has work on. This function is called on every update, and right before -// exiting a task. -function ensureRootIsScheduled(root, currentTime) { - var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as - // expired so we know to work on those next. +function FiberNode(tag, pendingProps, key, mode) { + // Instance + this.tag = tag; + this.key = key; + this.elementType = null; + this.type = null; + this.stateNode = null; // Fiber - markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority. + this.return = null; + this.child = null; + this.sibling = null; + this.index = 0; + this.ref = null; + this.refCleanup = null; + this.pendingProps = pendingProps; + this.memoizedProps = null; + this.updateQueue = null; + this.memoizedState = null; + this.dependencies = null; + this.mode = mode; // Effects - var nextLanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); + this.flags = NoFlags$1; + this.subtreeFlags = NoFlags$1; + this.deletions = null; + this.lanes = NoLanes; + this.childLanes = NoLanes; + this.alternate = null; - if (nextLanes === NoLanes) { - // Special case: There's nothing to work on. - if (existingCallbackNode !== null) { - cancelCallback(existingCallbackNode); - } + { + // 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). - root.callbackNode = null; - root.callbackPriority = NoLane; - return; - } // If this root is currently suspended and waiting for data to resolve, don't - // schedule a task to render it. We'll either wait for a ping, or wait to - // receive an update. + this.actualDuration = 0; + this.actualStartTime = -1; + this.selfBaseDuration = 0; + this.treeBaseDuration = 0; + } - if ( - workInProgressSuspendedReason === SuspendedOnData && - workInProgressRoot === root - ) { - root.callbackPriority = NoLane; - root.callbackNode = null; - return; - } // We use the highest priority lane to represent the priority of the callback. + { + // This isn't directly used but is handy for debugging internals: + this._debugSource = null; + this._debugOwner = null; + this._debugNeedsRemount = false; + this._debugHookTypes = null; - var newCallbackPriority = getHighestPriorityLane(nextLanes); // Check if there's an existing task. We may be able to reuse it. + if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { + Object.preventExtensions(this); + } + } +} // 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 existingCallbackPriority = root.callbackPriority; +function createFiber(tag, pendingProps, key, mode) { + // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors + return new FiberNode(tag, pendingProps, key, mode); +} - if ( - existingCallbackPriority === newCallbackPriority && // Special case related to `act`. If the currently scheduled task is a - // Scheduler task, rather than an `act` task, cancel it and re-scheduled - // on the `act` queue. - !( - ReactCurrentActQueue.current !== null && - existingCallbackNode !== fakeActCallbackNode - ) - ) { - { - // If we're going to re-use an existing task, it needs to exist. - // Assume that discrete update microtasks are non-cancellable and null. - // TODO: Temporary until we confirm this warning is not fired. - if ( - existingCallbackNode == null && - !includesSyncLane(existingCallbackPriority) - ) { - error( - "Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue." - ); - } - } // The priority hasn't changed. We can reuse the existing task. Exit. +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; - return; - } + if ($$typeof === REACT_FORWARD_REF_TYPE) { + return ForwardRef; + } - if (existingCallbackNode != null) { - // Cancel the existing callback. We'll schedule a new one below. - cancelCallback(existingCallbackNode); - } // Schedule a new callback. + if ($$typeof === REACT_MEMO_TYPE) { + return MemoComponent; + } + } - var newCallbackNode; + return IndeterminateComponent; +} // This is used to create an alternate fiber to do work on. - if (includesSyncLane(newCallbackPriority)) { - // Special case: Sync React callbacks are scheduled on a special - // internal queue - if (root.tag === LegacyRoot) { - if (ReactCurrentActQueue.isBatchingLegacy !== null) { - ReactCurrentActQueue.didScheduleLegacyUpdate = true; - } +function createWorkInProgress(current, pendingProps) { + var workInProgress = current.alternate; - scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root)); - } else { - scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)); - } + 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; { - // Flush the queue in a microtask. - if (ReactCurrentActQueue.current !== null) { - // Inside `act`, use our internal `act` queue so that these get flushed - // at the end of the current scope even when using the sync version - // of `act`. - ReactCurrentActQueue.current.push(flushSyncCallbacks); - } else { - scheduleMicrotask(function () { - // In Safari, appending an iframe forces microtasks to run. - // https://github.com/facebook/react/issues/22459 - // We don't support running callbacks in the middle of render - // or commit so we need to check against that. - if ( - (executionContext & (RenderContext | CommitContext)) === - NoContext - ) { - // Note that this would still prematurely flush the callbacks - // if this happens outside render or commit phase (e.g. in an event). - flushSyncCallbacks(); - } - }); - } + // DEV-only fields + workInProgress._debugSource = current._debugSource; + workInProgress._debugOwner = current._debugOwner; + workInProgress._debugHookTypes = current._debugHookTypes; } - newCallbackNode = null; + workInProgress.alternate = current; + current.alternate = workInProgress; } else { - var schedulerPriorityLevel; - - switch (lanesToEventPriority(nextLanes)) { - case DiscreteEventPriority: - schedulerPriorityLevel = ImmediatePriority; - break; + workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. - case ContinuousEventPriority: - schedulerPriorityLevel = UserBlockingPriority; - break; + workInProgress.type = current.type; // We already have an alternate. + // Reset the effect tag. - case DefaultEventPriority: - schedulerPriorityLevel = NormalPriority$1; - break; + workInProgress.flags = NoFlags$1; // The effects are no longer valid. - case IdleEventPriority: - schedulerPriorityLevel = IdlePriority; - break; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.deletions = null; - default: - schedulerPriorityLevel = NormalPriority$1; - break; + { + // 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; } + } // Reset all effects except static ones. + // Static effects are not specific to a render. - newCallbackNode = scheduleCallback( - schedulerPriorityLevel, - performConcurrentWorkOnRoot.bind(null, root) - ); - } + workInProgress.flags = current.flags & StaticMask; + workInProgress.childLanes = current.childLanes; + workInProgress.lanes = current.lanes; + workInProgress.child = current.child; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated during the render phase, so + // it cannot be shared with the current fiber. - root.callbackPriority = newCallbackPriority; - root.callbackNode = newCallbackNode; -} // This is the entry point for every concurrent task, i.e. anything that -// goes through Scheduler. + var currentDependencies = current.dependencies; + workInProgress.dependencies = + currentDependencies === null + ? null + : { + lanes: currentDependencies.lanes, + firstContext: currentDependencies.firstContext + }; // These will be overridden during the parent's reconciliation + + workInProgress.sibling = current.sibling; + workInProgress.index = current.index; + workInProgress.ref = current.ref; + workInProgress.refCleanup = current.refCleanup; -function performConcurrentWorkOnRoot(root, didTimeout) { { - resetNestedUpdateFlag(); - } // Since we know we're in a React event, we can clear the current - // event time. The next update will compute a new event time. + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; + } - currentEventTime = NoTimestamp; - currentEventTransitionLane = NoLanes; + { + workInProgress._debugNeedsRemount = current._debugNeedsRemount; - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); - } // Flush any pending passive effects before deciding which lanes to work on, - // in case they schedule additional work. + switch (workInProgress.tag) { + case IndeterminateComponent: + case FunctionComponent: + case SimpleMemoComponent: + workInProgress.type = resolveFunctionForHotReloading(current.type); + break; - var originalCallbackNode = root.callbackNode; - var didFlushPassiveEffects = flushPassiveEffects(); + case ClassComponent: + workInProgress.type = resolveClassForHotReloading(current.type); + break; - if (didFlushPassiveEffects) { - // Something in the passive effect phase may have canceled the current task. - // Check if the task node for this root was changed. - if (root.callbackNode !== originalCallbackNode) { - // The current task was canceled. Exit. We don't need to call - // `ensureRootIsScheduled` because the check above implies either that - // there's a new task, or that there's no remaining work on this root. - return null; + case ForwardRef: + workInProgress.type = resolveForwardRefForHotReloading(current.type); + break; } - } // Determine the next lanes to work on, using the fields stored - // on the root. - - var lanes = getNextLanes( - root, - root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes - ); + } - if (lanes === NoLanes) { - // Defensive coding. This is never expected to happen. - return null; - } // We disable time-slicing in some cases: if the work has been CPU-bound - // for too long ("expired" work, to prevent starvation), or we're in - // sync-updates-by-default mode. - // TODO: We only check `didTimeout` defensively, to account for a Scheduler - // bug we're still investigating. Once the bug in Scheduler is fixed, - // we can remove this, since we track expiration ourselves. + return workInProgress; +} // Used to reuse a Fiber for a second pass. - var shouldTimeSlice = - !includesBlockingLane(root, lanes) && - !includesExpiredLane(root, lanes) && - (disableSchedulerTimeoutInWorkLoop || !didTimeout); - var exitStatus = shouldTimeSlice - ? renderRootConcurrent(root, lanes) - : renderRootSync(root, lanes); +function resetWorkInProgress(workInProgress, renderLanes) { + // This resets the Fiber to what createFiber or createWorkInProgress would + // have set the values to before during the first pass. Ideally this wouldn't + // be necessary but unfortunately many code paths reads from the workInProgress + // when they should be reading from current and writing to workInProgress. + // We assume pendingProps, index, key, ref, return are still untouched to + // avoid doing another reconciliation. + // Reset the effect flags but keep any Placement tags, since that's something + // that child fiber is setting, not the reconciliation. + workInProgress.flags &= StaticMask | Placement; // The effects are no longer valid. - if (exitStatus !== RootInProgress) { - if (exitStatus === RootErrored) { - // If something threw an error, try rendering one more time. We'll - // render synchronously to block concurrent data mutations, and we'll - // includes all pending updates are included. If it still fails after - // the second attempt, we'll give up and commit the resulting tree. - var originallyAttemptedLanes = lanes; - var errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes - ); + var current = workInProgress.alternate; - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes - ); - } - } + if (current === null) { + // Reset to createFiber's initial values. + workInProgress.childLanes = NoLanes; + workInProgress.lanes = renderLanes; + workInProgress.child = null; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.memoizedProps = null; + workInProgress.memoizedState = null; + workInProgress.updateQueue = null; + workInProgress.dependencies = null; + workInProgress.stateNode = null; - if (exitStatus === RootFatalErrored) { - var fatalError = workInProgressRootFatalError; - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - throw fatalError; + { + // Note: We don't reset the actualTime counts. It's useful to accumulate + // actual time across multiple render passes. + workInProgress.selfBaseDuration = 0; + workInProgress.treeBaseDuration = 0; } + } else { + // Reset to the cloned values that createWorkInProgress would've. + workInProgress.childLanes = current.childLanes; + workInProgress.lanes = current.lanes; + workInProgress.child = current.child; + workInProgress.subtreeFlags = NoFlags$1; + workInProgress.deletions = null; + workInProgress.memoizedProps = current.memoizedProps; + workInProgress.memoizedState = current.memoizedState; + workInProgress.updateQueue = current.updateQueue; // Needed because Blocks store data on type. - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended(root, lanes); - } else { - // The render completed. - // Check if this render may have yielded to a concurrent event, and if so, - // confirm that any newly rendered stores are consistent. - // TODO: It's possible that even a concurrent render may never have yielded - // to the main thread, if it was fast enough, or if it expired. We could - // skip the consistency check in that case, too. - var renderWasConcurrent = !includesBlockingLane(root, lanes); - var finishedWork = root.current.alternate; - - if ( - renderWasConcurrent && - !isRenderConsistentWithExternalStores(finishedWork) - ) { - // A store was mutated in an interleaved event. Render again, - // synchronously, to block further mutations. - exitStatus = renderRootSync(root, lanes); // We need to check again if something threw - - if (exitStatus === RootErrored) { - var _originallyAttemptedLanes = lanes; - - var _errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - _originallyAttemptedLanes - ); - - if (_errorRetryLanes !== NoLanes) { - lanes = _errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - _originallyAttemptedLanes, - _errorRetryLanes - ); // We assume the tree is now consistent because we didn't yield to any - // concurrent events. - } - } + workInProgress.type = current.type; // Clone the dependencies object. This is mutated during the render phase, so + // it cannot be shared with the current fiber. - if (exitStatus === RootFatalErrored) { - var _fatalError = workInProgressRootFatalError; - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - throw _fatalError; - } // FIXME: Need to check for RootDidNotComplete again. The factoring here - // isn't ideal. - } // We now have a consistent tree. The next step is either to commit it, - // or, if something suspended, wait to commit it after a timeout. + var currentDependencies = current.dependencies; + workInProgress.dependencies = + currentDependencies === null + ? null + : { + lanes: currentDependencies.lanes, + firstContext: currentDependencies.firstContext + }; - root.finishedWork = finishedWork; - root.finishedLanes = lanes; - finishConcurrentRender(root, exitStatus, lanes); + { + // Note: We don't reset the actualTime counts. It's useful to accumulate + // actual time across multiple render passes. + workInProgress.selfBaseDuration = current.selfBaseDuration; + workInProgress.treeBaseDuration = current.treeBaseDuration; } } - ensureRootIsScheduled(root, now$1()); - - if (root.callbackNode === originalCallbackNode) { - // The task node scheduled for this root is the same one that's - // currently executed. Need to return a continuation. - return performConcurrentWorkOnRoot.bind(null, root); - } - - return null; + return workInProgress; } - -function recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes +function createHostRootFiber( + tag, + isStrictMode, + concurrentUpdatesByDefaultOverride ) { - // If an error occurred during hydration, discard server response and fall - // back to client side render. - // Before rendering again, save the errors from the previous attempt. - var errorsFromFirstAttempt = workInProgressRootConcurrentErrors; - var wasRootDehydrated = isRootDehydrated(root); + var mode; - if (wasRootDehydrated) { - // The shell failed to hydrate. Set a flag to force a client rendering - // during the next attempt. To do this, we call prepareFreshStack now - // to create the root work-in-progress fiber. This is a bit weird in terms - // of factoring, because it relies on renderRootSync not calling - // prepareFreshStack again in the call below, which happens because the - // root and lanes haven't changed. - // - // TODO: I think what we should do is set ForceClientRender inside - // throwException, like we do for nested Suspense boundaries. The reason - // it's here instead is so we can switch to the synchronous work loop, too. - // Something to consider for a future refactor. - var rootWorkInProgress = prepareFreshStack(root, errorRetryLanes); - rootWorkInProgress.flags |= ForceClientRender; + if (tag === ConcurrentRoot) { + mode = ConcurrentMode; - { - errorHydratingContainer(root.containerInfo); + if (isStrictMode === true || createRootStrictEffectsByDefault) { + mode |= StrictLegacyMode | StrictEffectsMode; + } + + if ( + // Only for internal experiments. + concurrentUpdatesByDefaultOverride + ) { + mode |= ConcurrentUpdatesByDefaultMode; } + } else { + mode = NoMode; } - var exitStatus = renderRootSync(root, errorRetryLanes); + if (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; + } - if (exitStatus !== RootErrored) { - // Successfully finished rendering on retry - if (workInProgressRootDidAttachPingListener && !wasRootDehydrated) { - // During the synchronous render, we attached additional ping listeners. - // This is highly suggestive of an uncached promise (though it's not the - // only reason this would happen). If it was an uncached promise, then - // it may have masked a downstream error from ocurring without actually - // fixing it. Example: - // - // use(Promise.resolve('uncached')) - // throw new Error('Oops!') - // - // When this happens, there's a conflict between blocking potential - // concurrent data races and unwrapping uncached promise values. We - // have to choose one or the other. Because the data race recovery is - // a last ditch effort, we'll disable it. - root.errorRecoveryDisabledLanes = mergeLanes( - root.errorRecoveryDisabledLanes, - originallyAttemptedLanes - ); // Mark the current render as suspended and force it to restart. Once - // these lanes finish successfully, we'll re-enable the error recovery - // mechanism for subsequent updates. + return createFiber(HostRoot, null, null, mode); +} +function createFiberFromTypeAndProps( + type, // React$ElementType + key, + pendingProps, + owner, + mode, + lanes +) { + var fiberTag = IndeterminateComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. - workInProgressRootInterleavedUpdatedLanes |= originallyAttemptedLanes; - return RootSuspendedWithDelay; - } // The errors from the failed first attempt have been recovered. Add - // them to the collection of recoverable errors. We'll log them in the - // commit phase. + var resolvedType = type; - var errorsFromSecondAttempt = workInProgressRootRecoverableErrors; - workInProgressRootRecoverableErrors = errorsFromFirstAttempt; // The errors from the second attempt should be queued after the errors - // from the first attempt, to preserve the causal sequence. + if (typeof type === "function") { + if (shouldConstruct(type)) { + fiberTag = ClassComponent; - if (errorsFromSecondAttempt !== null) { - queueRecoverableErrors(errorsFromSecondAttempt); + { + resolvedType = resolveClassForHotReloading(resolvedType); + } + } else { + { + resolvedType = resolveFunctionForHotReloading(resolvedType); + } } - } + } else if (typeof type === "string") { + { + var hostContext = getHostContext(); + fiberTag = isHostHoistableType(type, pendingProps, hostContext) + ? HostHoistable + : isHostSingletonType(type) + ? HostSingleton + : HostComponent; + } + } else { + getTag: switch (type) { + case REACT_FRAGMENT_TYPE: + return createFiberFromFragment(pendingProps.children, mode, lanes, key); - return exitStatus; -} + case REACT_STRICT_MODE_TYPE: + fiberTag = Mode; + mode |= StrictLegacyMode; -function queueRecoverableErrors(errors) { - if (workInProgressRootRecoverableErrors === null) { - workInProgressRootRecoverableErrors = errors; - } else { - // $FlowFixMe[method-unbinding] - workInProgressRootRecoverableErrors.push.apply( - workInProgressRootRecoverableErrors, - errors - ); - } -} + if ((mode & ConcurrentMode) !== NoMode) { + // Strict effects should never run on legacy roots + mode |= StrictEffectsMode; + } -function finishConcurrentRender(root, exitStatus, lanes) { - switch (exitStatus) { - case RootInProgress: - case RootFatalErrored: { - throw new Error("Root did not complete. This is a bug in React."); - } - // Flow knows about invariant, so it complains if I add a break - // statement, but eslint doesn't know about invariant, so it complains - // if I do. eslint-disable-next-line no-fallthrough + break; - case RootErrored: { - // We should have already attempted to retry this tree. If we reached - // this point, it errored again. Commit it. - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ); - break; - } + case REACT_PROFILER_TYPE: + return createFiberFromProfiler(pendingProps, mode, lanes, key); - case RootSuspended: { - markRootSuspended(root, lanes); // We have an acceptable loading state. We need to figure out if we - // should immediately commit it or wait a bit. + case REACT_SUSPENSE_TYPE: + return createFiberFromSuspense(pendingProps, mode, lanes, key); - if ( - includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope - !shouldForceFlushFallbacksInDEV() - ) { - // This render only included retries, no updates. Throttle committing - // retries so that we don't show too many loading states too quickly. - var msUntilTimeout = - globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now$1(); // Don't bother with a very short suspense time. + case REACT_SUSPENSE_LIST_TYPE: + return createFiberFromSuspenseList(pendingProps, mode, lanes, key); - if (msUntilTimeout > 10) { - var nextLanes = getNextLanes(root, NoLanes); + case REACT_OFFSCREEN_TYPE: + return createFiberFromOffscreen(pendingProps, mode, lanes, key); - if (nextLanes !== NoLanes) { - // There's additional work on this root. - break; - } // The render is suspended, it hasn't timed out, and there's no - // lower priority work to do. Instead of committing the fallback - // immediately, wait for more data to arrive. + case REACT_LEGACY_HIDDEN_TYPE: { + return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); + } - root.timeoutHandle = scheduleTimeout( - commitRoot.bind( - null, - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ), - msUntilTimeout - ); - break; - } - } // The work expired. Commit immediately. + // eslint-disable-next-line no-fallthrough - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ); - break; - } + case REACT_SCOPE_TYPE: { + return createFiberFromScope(type, pendingProps, mode, lanes, key); + } - case RootSuspendedWithDelay: { - markRootSuspended(root, lanes); + // eslint-disable-next-line no-fallthrough - if (includesOnlyTransitions(lanes)) { - // This is a transition, so we should exit without committing a - // placeholder and without scheduling a timeout. Delay indefinitely - // until we receive more data. - break; + case REACT_CACHE_TYPE: { + return createFiberFromCache(pendingProps, mode, lanes, key); } - if (!shouldForceFlushFallbacksInDEV()) { - // This is not a transition, but we did trigger an avoided state. - // Schedule a placeholder to display after a short delay, using the Just - // Noticeable Difference. - // TODO: Is the JND optimization worth the added complexity? If this is - // the only reason we track the event time, then probably not. - // Consider removing. - var mostRecentEventTime = getMostRecentEventTime(root, lanes); - var eventTimeMs = mostRecentEventTime; - var timeElapsedMs = now$1() - eventTimeMs; + // eslint-disable-next-line no-fallthrough - var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time. + case REACT_TRACING_MARKER_TYPE: + if (enableTransitionTracing) { + return createFiberFromTracingMarker(pendingProps, mode, lanes, key); + } - if (_msUntilTimeout > 10) { - // Instead of committing the fallback immediately, wait for more data - // to arrive. - root.timeoutHandle = scheduleTimeout( - commitRoot.bind( - null, - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ), - _msUntilTimeout - ); + // eslint-disable-next-line no-fallthrough + + case REACT_DEBUG_TRACING_MODE_TYPE: + if (enableDebugTracing) { + fiberTag = Mode; + mode |= DebugTracingMode; break; } - } // Commit the placeholder. - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ); - break; - } + // eslint-disable-next-line no-fallthrough - case RootCompleted: { - // The work completed. Ready to commit. - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ); - break; - } + default: { + if (typeof type === "object" && type !== null) { + switch (type.$$typeof) { + case REACT_PROVIDER_TYPE: + fiberTag = ContextProvider; + break getTag; - default: { - throw new Error("Unknown root exit status."); - } - } -} + case REACT_CONTEXT_TYPE: + // This is a consumer + fiberTag = ContextConsumer; + break getTag; -function isRenderConsistentWithExternalStores(finishedWork) { - // Search the rendered tree for external store reads, and check whether the - // stores were mutated in a concurrent event. Intentionally using an iterative - // loop instead of recursion so we can exit early. - var node = finishedWork; + case REACT_FORWARD_REF_TYPE: + fiberTag = ForwardRef; - while (true) { - if (node.flags & StoreConsistency) { - var updateQueue = node.updateQueue; + { + resolvedType = resolveForwardRefForHotReloading(resolvedType); + } - if (updateQueue !== null) { - var checks = updateQueue.stores; + break getTag; - if (checks !== null) { - for (var i = 0; i < checks.length; i++) { - var check = checks[i]; - var getSnapshot = check.getSnapshot; - var renderedValue = check.value; + case REACT_MEMO_TYPE: + fiberTag = MemoComponent; + break getTag; - try { - if (!objectIs(getSnapshot(), renderedValue)) { - // Found an inconsistent store. - return false; - } - } catch (error) { - // If `getSnapshot` throws, return `false`. This will schedule - // a re-render, and the error will be rethrown during render. - return false; - } + case REACT_LAZY_TYPE: + fiberTag = LazyComponent; + resolvedType = null; + break getTag; } } - } - } - var child = node.child; + var info = ""; - if (node.subtreeFlags & StoreConsistency && child !== null) { - child.return = node; - node = child; - continue; - } + { + if ( + type === undefined || + (typeof type === "object" && + type !== null && + Object.keys(type).length === 0) + ) { + info += + " You likely forgot to export your component from the file " + + "it's defined in, or you might have mixed up default and " + + "named imports."; + } - if (node === finishedWork) { - return true; - } + var ownerName = owner ? getComponentNameFromFiber(owner) : null; - while (node.sibling === null) { - if (node.return === null || node.return === finishedWork) { - return true; - } + if (ownerName) { + info += "\n\nCheck the render method of `" + ownerName + "`."; + } + } - node = node.return; + throw new Error( + "Element type is invalid: expected a string (for built-in " + + "components) or a class/function (for composite components) " + + ("but got: " + (type == null ? type : typeof type) + "." + info) + ); + } } + } - node.sibling.return = node.return; - node = node.sibling; - } // Flow doesn't know this is unreachable, but eslint does - // eslint-disable-next-line no-unreachable + var fiber = createFiber(fiberTag, pendingProps, key, mode); + fiber.elementType = type; + fiber.type = resolvedType; + fiber.lanes = lanes; - return true; + { + fiber._debugOwner = owner; + } + + return fiber; } +function createFiberFromElement(element, mode, lanes) { + var owner = null; -function markRootSuspended(root, suspendedLanes) { - // When suspending, we should always exclude lanes that were pinged or (more - // rarely, since we try to avoid it) updated during the render phase. - // TODO: Lol maybe there's a better way to factor this besides this - // obnoxiously named function :) - suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes); - suspendedLanes = removeLanes( - suspendedLanes, - workInProgressRootInterleavedUpdatedLanes + { + owner = element._owner; + } + + var type = element.type; + var key = element.key; + var pendingProps = element.props; + var fiber = createFiberFromTypeAndProps( + type, + key, + pendingProps, + owner, + mode, + lanes ); - markRootSuspended$1(root, suspendedLanes); -} // This is the entry point for synchronous tasks that don't go -// through Scheduler -function performSyncWorkOnRoot(root) { { - syncNestedUpdateFlag(); + fiber._debugSource = element._source; + fiber._debugOwner = element._owner; } - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); + return fiber; +} +function createFiberFromFragment(elements, mode, lanes, key) { + var fiber = createFiber(Fragment, elements, key, mode); + fiber.lanes = lanes; + return fiber; +} + +function createFiberFromScope(scope, pendingProps, mode, lanes, key) { + var fiber = createFiber(ScopeComponent, pendingProps, key, mode); + fiber.type = scope; + fiber.elementType = scope; + fiber.lanes = lanes; + return fiber; +} + +function createFiberFromProfiler(pendingProps, mode, lanes, key) { + { + if (typeof pendingProps.id !== "string") { + error( + 'Profiler must specify an "id" of type `string` as a prop. Received the type `%s` instead.', + typeof pendingProps.id + ); + } } - flushPassiveEffects(); - var lanes = getNextLanes(root, NoLanes); + var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); + fiber.elementType = REACT_PROFILER_TYPE; + fiber.lanes = lanes; - if (!includesSyncLane(lanes)) { - // There's no remaining sync work left. - ensureRootIsScheduled(root, now$1()); - return null; + { + fiber.stateNode = { + effectDuration: 0, + passiveEffectDuration: 0 + }; } - var exitStatus = renderRootSync(root, lanes); + return fiber; +} - if (root.tag !== LegacyRoot && exitStatus === RootErrored) { - // If something threw an error, try rendering one more time. We'll render - // synchronously to block concurrent data mutations, and we'll includes - // all pending updates are included. If it still fails after the second - // attempt, we'll give up and commit the resulting tree. - var originallyAttemptedLanes = lanes; - var errorRetryLanes = getLanesToRetrySynchronouslyOnError( - root, - originallyAttemptedLanes - ); +function createFiberFromSuspense(pendingProps, mode, lanes, key) { + var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); + fiber.elementType = REACT_SUSPENSE_TYPE; + fiber.lanes = lanes; + return fiber; +} +function createFiberFromSuspenseList(pendingProps, mode, lanes, key) { + var fiber = createFiber(SuspenseListComponent, pendingProps, key, mode); + fiber.elementType = REACT_SUSPENSE_LIST_TYPE; + fiber.lanes = lanes; + return fiber; +} +function createFiberFromOffscreen(pendingProps, mode, lanes, key) { + var fiber = createFiber(OffscreenComponent, pendingProps, key, mode); + fiber.elementType = REACT_OFFSCREEN_TYPE; + fiber.lanes = lanes; + var primaryChildInstance = { + _visibility: OffscreenVisible, + _pendingVisibility: OffscreenVisible, + _pendingMarkers: null, + _retryCache: null, + _transitions: null, + _current: null, + detach: function () { + return detachOffscreenInstance(primaryChildInstance); + }, + attach: function () { + return attachOffscreenInstance(primaryChildInstance); + } + }; + fiber.stateNode = primaryChildInstance; + return fiber; +} +function createFiberFromLegacyHidden(pendingProps, mode, lanes, key) { + var fiber = createFiber(LegacyHiddenComponent, pendingProps, key, mode); + fiber.elementType = REACT_LEGACY_HIDDEN_TYPE; + fiber.lanes = lanes; // Adding a stateNode for legacy hidden because it's currently using + // the offscreen implementation, which depends on a state node - if (errorRetryLanes !== NoLanes) { - lanes = errorRetryLanes; - exitStatus = recoverFromConcurrentError( - root, - originallyAttemptedLanes, - errorRetryLanes - ); + var instance = { + _visibility: OffscreenVisible, + _pendingVisibility: OffscreenVisible, + _pendingMarkers: null, + _transitions: null, + _retryCache: null, + _current: null, + detach: function () { + return detachOffscreenInstance(instance); + }, + attach: function () { + return attachOffscreenInstance(instance); } - } + }; + fiber.stateNode = instance; + return fiber; +} +function createFiberFromCache(pendingProps, mode, lanes, key) { + var fiber = createFiber(CacheComponent, pendingProps, key, mode); + fiber.elementType = REACT_CACHE_TYPE; + fiber.lanes = lanes; + return fiber; +} +function createFiberFromTracingMarker(pendingProps, mode, lanes, key) { + var fiber = createFiber(TracingMarkerComponent, pendingProps, key, mode); + fiber.elementType = REACT_TRACING_MARKER_TYPE; + fiber.lanes = lanes; + var tracingMarkerInstance = { + tag: TransitionTracingMarker, + transitions: null, + pendingBoundaries: null, + aborts: null, + name: pendingProps.name + }; + fiber.stateNode = tracingMarkerInstance; + return fiber; +} +function createFiberFromText(content, mode, lanes) { + var fiber = createFiber(HostText, content, null, mode); + fiber.lanes = lanes; + return fiber; +} +function createFiberFromHostInstanceForDeletion() { + var fiber = createFiber(HostComponent, null, null, NoMode); + fiber.elementType = "DELETED"; + return fiber; +} +function createFiberFromDehydratedFragment(dehydratedNode) { + var fiber = createFiber(DehydratedFragment, null, null, NoMode); + fiber.stateNode = dehydratedNode; + return fiber; +} +function createFiberFromPortal(portal, mode, lanes) { + var pendingProps = portal.children !== null ? portal.children : []; + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); + fiber.lanes = lanes; + 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. - if (exitStatus === RootFatalErrored) { - var fatalError = workInProgressRootFatalError; - prepareFreshStack(root, NoLanes); - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - throw fatalError; - } +function assignFiberPropertiesInDEV(target, source) { + if (target === null) { + // This Fiber's initial properties will always be overwritten. + // We only use a Fiber to ensure the same hidden class so DEV isn't slow. + target = createFiber(IndeterminateComponent, null, null, NoMode); + } // This is intentionally written as a list of all properties. + // We tried to use Object.assign() instead but this is called in + // the hottest path, and Object.assign() was too slow: + // https://github.com/facebook/react/issues/12502 + // This code is DEV-only so size is not a concern. - if (exitStatus === RootDidNotComplete) { - // The render unwound without completing the tree. This happens in special - // cases where need to exit the current render without producing a - // consistent tree or committing. - markRootSuspended(root, lanes); - ensureRootIsScheduled(root, now$1()); - return null; - } // We now have a consistent tree. Because this is a sync render, we - // will commit it even if something suspended. + target.tag = source.tag; + target.key = source.key; + target.elementType = source.elementType; + target.type = source.type; + target.stateNode = source.stateNode; + target.return = source.return; + target.child = source.child; + target.sibling = source.sibling; + target.index = source.index; + target.ref = source.ref; + target.refCleanup = source.refCleanup; + target.pendingProps = source.pendingProps; + target.memoizedProps = source.memoizedProps; + target.updateQueue = source.updateQueue; + target.memoizedState = source.memoizedState; + target.dependencies = source.dependencies; + target.mode = source.mode; + target.flags = source.flags; + target.subtreeFlags = source.subtreeFlags; + target.deletions = source.deletions; + target.lanes = source.lanes; + target.childLanes = source.childLanes; + target.alternate = source.alternate; - var finishedWork = root.current.alternate; - root.finishedWork = finishedWork; - root.finishedLanes = lanes; - commitRoot( - root, - workInProgressRootRecoverableErrors, - workInProgressTransitions - ); // Before exiting, make sure there's a callback scheduled for the next - // pending level. + { + target.actualDuration = source.actualDuration; + target.actualStartTime = source.actualStartTime; + target.selfBaseDuration = source.selfBaseDuration; + target.treeBaseDuration = source.treeBaseDuration; + } - ensureRootIsScheduled(root, now$1()); - return null; + target._debugSource = source._debugSource; + target._debugOwner = source._debugOwner; + target._debugNeedsRemount = source._debugNeedsRemount; + target._debugHookTypes = source._debugHookTypes; + return target; } -function flushRoot(root, lanes) { - if (lanes !== NoLanes) { - markRootEntangled(root, mergeLanes(lanes, SyncLane)); - ensureRootIsScheduled(root, now$1()); +function FiberRootNode( + containerInfo, // $FlowFixMe[missing-local-annot] + tag, + hydrate, + identifierPrefix, + onRecoverableError +) { + this.tag = tag; + this.containerInfo = containerInfo; + this.pendingChildren = null; + this.current = null; + this.pingCache = null; + this.finishedWork = null; + this.timeoutHandle = noTimeout; + this.context = null; + this.pendingContext = null; + this.callbackNode = null; + this.callbackPriority = NoLane; + this.eventTimes = createLaneMap(NoLanes); + this.expirationTimes = createLaneMap(NoTimestamp); + this.pendingLanes = NoLanes; + this.suspendedLanes = NoLanes; + this.pingedLanes = NoLanes; + this.expiredLanes = NoLanes; + this.mutableReadLanes = NoLanes; + this.finishedLanes = NoLanes; + this.errorRecoveryDisabledLanes = NoLanes; + this.entangledLanes = NoLanes; + this.entanglements = createLaneMap(NoLanes); + this.hiddenUpdates = createLaneMap(null); + this.identifierPrefix = identifierPrefix; + this.onRecoverableError = onRecoverableError; - if ((executionContext & (RenderContext | CommitContext)) === NoContext) { - resetRenderTimer(); - flushSyncCallbacks(); - } + { + this.pooledCache = null; + this.pooledCacheLanes = NoLanes; } -} -function getExecutionContext() { - return executionContext; -} -function batchedUpdates(fn, a) { - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; - try { - return fn(a); - } finally { - executionContext = prevExecutionContext; // If there were legacy sync updates, flush them at the end of the outer - // most batchedUpdates-like method. + { + this.mutableSourceEagerHydrationData = null; + } - if ( - executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode. - !ReactCurrentActQueue.isBatchingLegacy - ) { - resetRenderTimer(); - flushSyncCallbacksOnlyInLegacyMode(); - } + { + this.hydrationCallbacks = null; } -} -function discreteUpdates(fn, a, b, c, d) { - var previousPriority = getCurrentUpdatePriority$1(); - var prevTransition = ReactCurrentBatchConfig.transition; - try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(DiscreteEventPriority); - return fn(a, b, c, d); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; + this.incompleteTransitions = new Map(); - if (executionContext === NoContext) { - resetRenderTimer(); + if (enableTransitionTracing) { + this.transitionCallbacks = null; + var transitionLanesMap = (this.transitionLanes = []); + + for (var i = 0; i < TotalLanes; i++) { + transitionLanesMap.push(null); } } -} // Overload the definition to the two valid signatures. -// Warning, this opts-out of checking the function body. -// eslint-disable-next-line no-unused-vars -// eslint-disable-next-line no-redeclare -// eslint-disable-next-line no-redeclare -function flushSync$1(fn) { - // In legacy mode, we flush pending passive effects at the beginning of the - // next event, not at the end of the previous one. - if ( - rootWithPendingPassiveEffects !== null && - rootWithPendingPassiveEffects.tag === LegacyRoot && - (executionContext & (RenderContext | CommitContext)) === NoContext - ) { - flushPassiveEffects(); + { + this.effectDuration = 0; + this.passiveEffectDuration = 0; } - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; - var prevTransition = ReactCurrentBatchConfig.transition; - var previousPriority = getCurrentUpdatePriority$1(); - - try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(DiscreteEventPriority); + { + this.memoizedUpdaters = new Set(); + var pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []); - if (fn) { - return fn(); - } else { - return undefined; + for (var _i = 0; _i < TotalLanes; _i++) { + pendingUpdatersLaneMap.push(new Set()); } - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; - executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch. - // Note that this will happen even if batchedUpdates is higher up - // the stack. + } - if ((executionContext & (RenderContext | CommitContext)) === NoContext) { - flushSyncCallbacks(); + { + switch (tag) { + case ConcurrentRoot: + this._debugRootType = hydrate ? "hydrateRoot()" : "createRoot()"; + break; + + case LegacyRoot: + this._debugRootType = hydrate ? "hydrate()" : "render()"; + break; } } } -function isAlreadyRendering() { - // Used by the renderer to print a warning if certain APIs are called from - // the wrong context. - return (executionContext & (RenderContext | CommitContext)) !== NoContext; -} -function isInvalidExecutionContextForEventFunction() { - // Used to throw if certain APIs are called from the wrong context. - return (executionContext & RenderContext) !== NoContext; -} -function flushControlled(fn) { - var prevExecutionContext = executionContext; - executionContext |= BatchedContext; - var prevTransition = ReactCurrentBatchConfig.transition; - var previousPriority = getCurrentUpdatePriority$1(); - try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(DiscreteEventPriority); - fn(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; - executionContext = prevExecutionContext; +function createFiberRoot( + containerInfo, + tag, + hydrate, + initialChildren, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, // TODO: We have several of these arguments that are conceptually part of the + // host config, but because they are passed in at runtime, we have to thread + // them through the root constructor. Perhaps we should put them all into a + // single type, like a DynamicHostConfig that is defined by the renderer. + identifierPrefix, + onRecoverableError, + transitionCallbacks +) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + var root = new FiberRootNode( + containerInfo, + tag, + hydrate, + identifierPrefix, + onRecoverableError + ); - if (executionContext === NoContext) { - // Flush the immediate callbacks that were scheduled during this batch - resetRenderTimer(); - flushSyncCallbacks(); - } + { + root.hydrationCallbacks = hydrationCallbacks; } -} // This is called by the HiddenContext module when we enter or leave a -// hidden subtree. The stack logic is managed there because that's the only -// place that ever modifies it. Which module it lives in doesn't matter for -// performance because this function will get inlined regardless -function setRenderLanes(subtreeRenderLanes) { - renderLanes = subtreeRenderLanes; -} -function getRenderLanes() { - return renderLanes; -} + if (enableTransitionTracing) { + root.transitionCallbacks = transitionCallbacks; + } // Cyclic construction. This cheats the type system right now because + // stateNode is any. -function resetWorkInProgressStack() { - if (workInProgress === null) return; - var interruptedWork; + var uninitializedFiber = createHostRootFiber( + tag, + isStrictMode, + concurrentUpdatesByDefaultOverride + ); + root.current = uninitializedFiber; + uninitializedFiber.stateNode = root; - if (workInProgressSuspendedReason === NotSuspended) { - // Normal case. Work-in-progress hasn't started yet. Unwind all - // its parents. - interruptedWork = workInProgress.return; - } else { - // Work-in-progress is in suspended state. Reset the work loop and unwind - // both the suspended fiber and all its parents. - resetSuspendedWorkLoopOnUnwind(); - interruptedWork = workInProgress; - } + { + var initialCache = createCache(); + retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily + // for newly mounted boundaries during a render. In general, the + // pooledCache is always cleared from the root at the end of a render: + // it is either released when render commits, or moved to an Offscreen + // component if rendering suspends. Because the lifetime of the pooled + // cache is distinct from the main memoizedState.cache, it must be + // retained separately. - while (interruptedWork !== null) { - var current = interruptedWork.alternate; - unwindInterruptedWork(current, interruptedWork); - interruptedWork = interruptedWork.return; + root.pooledCache = initialCache; + retainCache(initialCache); + var initialState = { + element: initialChildren, + isDehydrated: hydrate, + cache: initialCache + }; + uninitializedFiber.memoizedState = initialState; } - workInProgress = null; + initializeUpdateQueue(uninitializedFiber); + return root; } -function prepareFreshStack(root, lanes) { - root.finishedWork = null; - root.finishedLanes = NoLanes; - var timeoutHandle = root.timeoutHandle; - - if (timeoutHandle !== noTimeout) { - // The root previous suspended and scheduled a timeout to commit a fallback - // state. Now that we have additional work, cancel the timeout. - root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above - - cancelTimeout(timeoutHandle); - } +var ReactVersion = "18.3.0-www-classic-036f93df"; - resetWorkInProgressStack(); - workInProgressRoot = root; - var rootWorkInProgress = createWorkInProgress(root.current, null); - workInProgress = rootWorkInProgress; - workInProgressRootRenderLanes = renderLanes = lanes; - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - workInProgressRootDidAttachPingListener = false; - workInProgressRootExitStatus = RootInProgress; - workInProgressRootFatalError = null; - workInProgressRootSkippedLanes = NoLanes; - workInProgressRootInterleavedUpdatedLanes = NoLanes; - workInProgressRootPingedLanes = NoLanes; - workInProgressRootConcurrentErrors = null; - workInProgressRootRecoverableErrors = null; - finishQueueingConcurrentUpdates(); +function createPortal$1( + children, + containerInfo, // TODO: figure out the API for cross-renderer implementation. + implementation +) { + var key = + arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; { - ReactStrictModeWarnings.discardPendingWarnings(); + checkKeyStringCoercion(key); } - return rootWorkInProgress; + return { + // This tag allow us to uniquely identify this as a React Portal + $$typeof: REACT_PORTAL_TYPE, + key: key == null ? null : "" + key, + children: children, + containerInfo: containerInfo, + implementation: implementation + }; } -function resetSuspendedWorkLoopOnUnwind() { - // Reset module-level state that was set during the render phase. - resetContextDependencies(); - resetHooksOnUnwind(); - resetChildReconcilerOnUnwind(); -} +// Might add PROFILE later. -function handleThrow(root, thrownValue) { - // A component threw an exception. Usually this is because it suspended, but - // it also includes regular program errors. - // - // We're either going to unwind the stack to show a Suspense or error - // boundary, or we're going to replay the component again. Like after a - // promise resolves. - // - // Until we decide whether we're going to unwind or replay, we should preserve - // the current state of the work loop without resetting anything. - // - // If we do decide to unwind the stack, module-level variables will be reset - // in resetSuspendedWorkLoopOnUnwind. - // These should be reset immediately because they're only supposed to be set - // when React is executing user code. - resetHooksAfterThrow(); - resetCurrentFiber(); - ReactCurrentOwner$1.current = null; +var didWarnAboutNestedUpdates; +var didWarnAboutFindNodeInStrictMode; - if (thrownValue === SuspenseException) { - // This is a special type of exception used for Suspense. For historical - // reasons, the rest of the Suspense implementation expects the thrown value - // to be a thenable, because before `use` existed that was the (unstable) - // API for suspending. This implementation detail can change later, once we - // deprecate the old API in favor of `use`. - thrownValue = getSuspendedThenable(); - workInProgressSuspendedReason = shouldAttemptToSuspendUntilDataResolves() - ? SuspendedOnData - : SuspendedOnImmediate; - } else if (thrownValue === SelectiveHydrationException) { - // An update flowed into a dehydrated boundary. Before we can apply the - // update, we need to finish hydrating. Interrupt the work-in-progress - // render so we can restart at the hydration lane. - // - // The ideal implementation would be able to switch contexts without - // unwinding the current stack. - // - // We could name this something more general but as of now it's the only - // case where we think this should happen. - workInProgressSuspendedReason = SuspendedOnHydration; - } else { - // This is a regular error. - var isWakeable = - thrownValue !== null && - typeof thrownValue === "object" && - typeof thrownValue.then === "function"; - workInProgressSuspendedReason = isWakeable // A wakeable object was thrown by a legacy Suspense implementation. - ? // This has slightly different behavior than suspending with `use`. - SuspendedOnDeprecatedThrowPromise // This is a regular error. If something earlier in the component already - : // suspended, we must clear the thenable state to unblock the work loop. - SuspendedOnError; +{ + didWarnAboutNestedUpdates = false; + didWarnAboutFindNodeInStrictMode = {}; +} + +function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyContextObject; } - workInProgressThrownValue = thrownValue; - var erroredWork = workInProgress; + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); - if (erroredWork === null) { - // This is a fatal error - workInProgressRootExitStatus = RootFatalErrored; - workInProgressRootFatalError = thrownValue; - return; - } + if (fiber.tag === ClassComponent) { + var Component = fiber.type; - if (erroredWork.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(erroredWork, true); + if (isContextProvider(Component)) { + return processChildContext(fiber, Component, parentContext); + } } - if (enableSchedulingProfiler) { - markComponentRenderStopped(); + return parentContext; +} - switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - markComponentErrored( - erroredWork, - thrownValue, - workInProgressRootRenderLanes - ); - break; - } +function findHostInstanceWithWarning(component, methodName) { + { + var fiber = get(component); - case SuspendedOnData: - case SuspendedOnImmediate: - case SuspendedOnDeprecatedThrowPromise: - case SuspendedAndReadyToContinue: { - var wakeable = thrownValue; - markComponentSuspended( - erroredWork, - wakeable, - workInProgressRootRenderLanes + if (fiber === undefined) { + if (typeof component.render === "function") { + throw new Error("Unable to find node on an unmounted component."); + } else { + var keys = Object.keys(component).join(","); + throw new Error( + "Argument appears to not be a ReactComponent. Keys: " + keys ); - break; } } - } -} -function shouldAttemptToSuspendUntilDataResolves() { - // Check if there are other pending updates that might possibly unblock this - // component from suspending. This mirrors the check in - // renderDidSuspendDelayIfPossible. We should attempt to unify them somehow. - // TODO: Consider unwinding immediately, using the - // SuspendedOnHydration mechanism. - if ( - includesNonIdleWork(workInProgressRootSkippedLanes) || - includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes) - ) { - // Suspend normally. renderDidSuspendDelayIfPossible will handle - // interrupting the work loop. - return false; - } // TODO: We should be able to remove the equivalent check in - // finishConcurrentRender, and rely just on this one. + var hostFiber = findCurrentHostFiber(fiber); - if (includesOnlyTransitions(workInProgressRootRenderLanes)) { - // If we're rendering inside the "shell" of the app, it's better to suspend - // rendering and wait for the data to resolve. Otherwise, we should switch - // to a fallback and continue rendering. - return getShellBoundary() === null; - } + if (hostFiber === null) { + return null; + } - var handler = getSuspenseHandler(); + if (hostFiber.mode & StrictLegacyMode) { + var componentName = getComponentNameFromFiber(fiber) || "Component"; - if (handler === null); - else { - if (includesOnlyRetries(workInProgressRootRenderLanes)) { - // During a retry, we can suspend rendering if the nearest Suspense boundary - // is the boundary of the "shell", because we're guaranteed not to block - // any new content from appearing. - return handler === getShellBoundary(); + if (!didWarnAboutFindNodeInStrictMode[componentName]) { + didWarnAboutFindNodeInStrictMode[componentName] = true; + var previousFiber = current; + + try { + setCurrentFiber(hostFiber); + + if (fiber.mode & StrictLegacyMode) { + error( + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which is inside StrictMode. " + + "Instead, add a ref directly to the element you want to reference. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-find-node", + methodName, + methodName, + componentName + ); + } else { + error( + "%s is deprecated in StrictMode. " + + "%s was passed an instance of %s which renders StrictMode children. " + + "Instead, add a ref directly to the element you want to reference. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-find-node", + methodName, + methodName, + componentName + ); + } + } finally { + // Ideally this should reset to previous but this shouldn't be called in + // render and there's another warning for that anyway. + if (previousFiber) { + setCurrentFiber(previousFiber); + } else { + resetCurrentFiber(); + } + } + } } - } // For all other Lanes besides Transitions and Retries, we should not wait - // for the data to load. - // TODO: We should wait during Offscreen prerendering, too. - return false; + return getPublicInstance(hostFiber.stateNode); + } } -function pushDispatcher(container) { - prepareRendererToRender(container); - var prevDispatcher = ReactCurrentDispatcher.current; - ReactCurrentDispatcher.current = ContextOnlyDispatcher; +function createContainer( + containerInfo, + tag, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, + identifierPrefix, + onRecoverableError, + transitionCallbacks +) { + var hydrate = false; + var initialChildren = null; + return createFiberRoot( + containerInfo, + tag, + hydrate, + initialChildren, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, + identifierPrefix, + onRecoverableError, + transitionCallbacks + ); +} +function createHydrationContainer( + initialChildren, // TODO: Remove `callback` when we delete legacy mode. + callback, + containerInfo, + tag, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, + identifierPrefix, + onRecoverableError, + transitionCallbacks +) { + var hydrate = true; + var root = createFiberRoot( + containerInfo, + tag, + hydrate, + initialChildren, + hydrationCallbacks, + isStrictMode, + concurrentUpdatesByDefaultOverride, + identifierPrefix, + onRecoverableError, + transitionCallbacks + ); // TODO: Move this to FiberRoot constructor - if (prevDispatcher === null) { - // The React isomorphic package does not include a default dispatcher. - // Instead the first renderer will lazily attach one, in order to give - // nicer error messages. - return ContextOnlyDispatcher; - } else { - return prevDispatcher; - } -} + root.context = getContextForSubtree(null); // Schedule the initial render. In a hydration root, this is different from + // a regular update because the initial render must match was was rendered + // on the server. + // NOTE: This update intentionally doesn't have a payload. We're only using + // the update to schedule work on the root fiber (and, for legacy roots, to + // enqueue the callback if one is provided). -function popDispatcher(prevDispatcher) { - resetRendererAfterRender(); - ReactCurrentDispatcher.current = prevDispatcher; + var current = root.current; + var lane = requestUpdateLane(current); + var update = createUpdate(lane); + update.callback = + callback !== undefined && callback !== null ? callback : null; + var eventTime = requestEventTime(); + enqueueUpdate(current, update, lane); + scheduleInitialHydrationOnRoot(root, lane, eventTime); + return root; } - -function pushCacheDispatcher() { +function updateContainer(element, container, parentComponent, callback) { { - var prevCacheDispatcher = ReactCurrentCache.current; - ReactCurrentCache.current = DefaultCacheDispatcher; - return prevCacheDispatcher; + onScheduleRoot(container, element); } -} -function popCacheDispatcher(prevCacheDispatcher) { - { - ReactCurrentCache.current = prevCacheDispatcher; - } -} + var current$1 = container.current; + var lane = requestUpdateLane(current$1); -function markCommitTimeOfFallback() { - globalMostRecentFallbackTime = now$1(); -} -function markSkippedUpdateLanes(lane) { - workInProgressRootSkippedLanes = mergeLanes( - lane, - workInProgressRootSkippedLanes - ); -} -function renderDidSuspend() { - if (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootSuspended; + if (enableSchedulingProfiler) { + markRenderScheduled(lane); } -} -function renderDidSuspendDelayIfPossible() { - workInProgressRootExitStatus = RootSuspendedWithDelay; // Check if there are updates that we skipped tree that might have unblocked - // this render. - if ( - workInProgressRoot !== null && - (includesNonIdleWork(workInProgressRootSkippedLanes) || - includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes)) - ) { - // Mark the current render as suspended so that we switch to working on - // the updates that were skipped. Usually we only suspend at the end of - // the render phase. - // TODO: We should probably always mark the root as suspended immediately - // (inside this function), since by suspending at the end of the render - // phase introduces a potential mistake where we suspend lanes that were - // pinged or updated while we were rendering. - // TODO: Consider unwinding immediately, using the - // SuspendedOnHydration mechanism. - // $FlowFixMe[incompatible-call] need null check workInProgressRoot - markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes); - } -} -function renderDidError(error) { - if (workInProgressRootExitStatus !== RootSuspendedWithDelay) { - workInProgressRootExitStatus = RootErrored; - } + var context = getContextForSubtree(parentComponent); - if (workInProgressRootConcurrentErrors === null) { - workInProgressRootConcurrentErrors = [error]; + if (container.context === null) { + container.context = context; } else { - workInProgressRootConcurrentErrors.push(error); + container.pendingContext = context; } -} // Called during render to determine if anything has suspended. -// Returns false if we're not sure. -function renderHasNotSuspendedYet() { - // If something errored or completed, we can't really be sure, - // so those are false. - return workInProgressRootExitStatus === RootInProgress; -} // TODO: Over time, this function and renderRootConcurrent have become more -// and more similar. Not sure it makes sense to maintain forked paths. Consider -// unifying them again. + { + if (isRendering && current !== null && !didWarnAboutNestedUpdates) { + didWarnAboutNestedUpdates = true; -function renderRootSync(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(root.containerInfo); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. + error( + "Render methods should be a pure function of props and state; " + + "triggering nested component updates from render is not allowed. " + + "If necessary, trigger nested updates in componentDidUpdate.\n\n" + + "Check the render method of %s.", + getComponentNameFromFiber(current) || "Unknown" + ); + } + } - if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { - { - if (isDevToolsPresent) { - var memoizedUpdaters = root.memoizedUpdaters; + var update = createUpdate(lane); // Caution: React DevTools currently depends on this property + // being called "element". - if (memoizedUpdaters.size > 0) { - restorePendingUpdaters(root, workInProgressRootRenderLanes); - memoizedUpdaters.clear(); - } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. - // If we bailout on this work, we'll move them back (like above). - // It's important to move them now in case the work spawns more work at the same priority with different updaters. - // That way we can keep the current update and future updates separate. + update.payload = { + element: element + }; + callback = callback === undefined ? null : callback; - movePendingFibersToMemoized(root, lanes); + if (callback !== null) { + { + if (typeof callback !== "function") { + error( + "render(...): Expected the last optional `callback` argument to be a " + + "function. Instead received: %s.", + callback + ); } } - workInProgressTransitions = getTransitionsForLanes(root, lanes); - prepareFreshStack(root, lanes); + update.callback = callback; } - { - if (enableDebugTracing) { - logRenderStarted(lanes); - } + var root = enqueueUpdate(current$1, update, lane); + + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, current$1, lane, eventTime); + entangleTransitions(root, current$1, lane); } - if (enableSchedulingProfiler) { - markRenderStarted(lanes); + return lane; +} +function getPublicRootInstance(container) { + var containerFiber = container.current; + + if (!containerFiber.child) { + return null; } - outer: do { - try { - if ( - workInProgressSuspendedReason !== NotSuspended && - workInProgress !== null - ) { - // The work loop is suspended. During a synchronous render, we don't - // yield to the main thread. Immediately unwind the stack. This will - // trigger either a fallback or an error boundary. - // TODO: For discrete and "default" updates (anything that's not - // flushSync), we want to wait for the microtasks the flush before - // unwinding. Will probably implement this using renderRootConcurrent, - // or merge renderRootSync and renderRootConcurrent into the same - // function and fork the behavior some other way. - var unitOfWork = workInProgress; - var thrownValue = workInProgressThrownValue; + switch (containerFiber.child.tag) { + case HostSingleton: + case HostComponent: + return getPublicInstance(containerFiber.child.stateNode); - switch (workInProgressSuspendedReason) { - case SuspendedOnHydration: { - // Selective hydration. An update flowed into a dehydrated tree. - // Interrupt the current render so the work loop can switch to the - // hydration lane. - resetWorkInProgressStack(); - workInProgressRootExitStatus = RootDidNotComplete; - break outer; - } + default: + return containerFiber.child.stateNode; + } +} +function attemptSynchronousHydration(fiber) { + switch (fiber.tag) { + case HostRoot: { + var root = fiber.stateNode; - default: { - // Continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - unwindSuspendedUnitOfWork(unitOfWork, thrownValue); - break; - } - } + if (isRootDehydrated(root)) { + // Flush the first scheduled "update". + var lanes = getHighestPriorityPendingLanes(root); + flushRoot(root, lanes); } - workLoopSync(); break; - } catch (thrownValue) { - handleThrow(root, thrownValue); } - } while (true); - resetContextDependencies(); - executionContext = prevExecutionContext; - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); + case SuspenseComponent: { + flushSync$1(function () { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (workInProgress !== null) { - // This is a sync render, so we should have finished the whole tree. - throw new Error( - "Cannot commit an incomplete root. This error is likely caused by a " + - "bug in React. Please file an issue." - ); - } + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, SyncLane, eventTime); + } + }); // If we're still blocked after this, we need to increase + // the priority of any promises resolving within this + // boundary so that they next attempt also has higher pri. - { - if (enableDebugTracing) { - logRenderStopped(); + var retryLane = SyncLane; + markRetryLaneIfNotHydrated(fiber, retryLane); + break; } } +} - if (enableSchedulingProfiler) { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. - - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. +function markRetryLaneImpl(fiber, retryLane) { + var suspenseState = fiber.memoizedState; - finishQueueingConcurrentUpdates(); - return workInProgressRootExitStatus; -} // The work loop is an extremely hot path. Tell Closure not to inline it. + if (suspenseState !== null && suspenseState.dehydrated !== null) { + suspenseState.retryLane = higherPriorityLane( + suspenseState.retryLane, + retryLane + ); + } +} // Increases the priority of thenables when they resolve within this boundary. -/** @noinline */ +function markRetryLaneIfNotHydrated(fiber, retryLane) { + markRetryLaneImpl(fiber, retryLane); + var alternate = fiber.alternate; -function workLoopSync() { - // Perform work without checking if we need to yield between fiber. - while (workInProgress !== null) { - performUnitOfWork(workInProgress); + if (alternate) { + markRetryLaneImpl(alternate, retryLane); } } -function renderRootConcurrent(root, lanes) { - var prevExecutionContext = executionContext; - executionContext |= RenderContext; - var prevDispatcher = pushDispatcher(root.containerInfo); - var prevCacheDispatcher = pushCacheDispatcher(); // If the root or lanes have changed, throw out the existing stack - // and prepare a fresh one. Otherwise we'll continue where we left off. +function attemptDiscreteHydration(fiber) { + if (fiber.tag !== SuspenseComponent) { + // We ignore HostRoots here because we can't increase + // their priority and they should not suspend on I/O, + // since you have to wrap anything that might suspend in + // Suspense. + return; + } - if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) { - { - if (isDevToolsPresent) { - var memoizedUpdaters = root.memoizedUpdaters; + var lane = SyncLane; + var root = enqueueConcurrentRenderForLane(fiber, lane); - if (memoizedUpdaters.size > 0) { - restorePendingUpdaters(root, workInProgressRootRenderLanes); - memoizedUpdaters.clear(); - } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set. - // If we bailout on this work, we'll move them back (like above). - // It's important to move them now in case the work spawns more work at the same priority with different updaters. - // That way we can keep the current update and future updates separate. + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); + } - movePendingFibersToMemoized(root, lanes); - } - } + markRetryLaneIfNotHydrated(fiber, lane); +} +function attemptContinuousHydration(fiber) { + if (fiber.tag !== SuspenseComponent) { + // We ignore HostRoots here because we can't increase + // their priority and they should not suspend on I/O, + // since you have to wrap anything that might suspend in + // Suspense. + return; + } - workInProgressTransitions = getTransitionsForLanes(root, lanes); - resetRenderTimer(); - prepareFreshStack(root, lanes); + var lane = SelectiveHydrationLane; + var root = enqueueConcurrentRenderForLane(fiber, lane); + + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); } - { - if (enableDebugTracing) { - logRenderStarted(lanes); - } + markRetryLaneIfNotHydrated(fiber, lane); +} +function attemptHydrationAtCurrentPriority(fiber) { + if (fiber.tag !== SuspenseComponent) { + // We ignore HostRoots here because we can't increase + // their priority other than synchronously flush it. + return; } - if (enableSchedulingProfiler) { - markRenderStarted(lanes); + var lane = requestUpdateLane(fiber); + var root = enqueueConcurrentRenderForLane(fiber, lane); + + if (root !== null) { + var eventTime = requestEventTime(); + scheduleUpdateOnFiber(root, fiber, lane, eventTime); } - outer: do { - try { - if ( - workInProgressSuspendedReason !== NotSuspended && - workInProgress !== null - ) { - // The work loop is suspended. We need to either unwind the stack or - // replay the suspended component. - var unitOfWork = workInProgress; - var thrownValue = workInProgressThrownValue; + markRetryLaneIfNotHydrated(fiber, lane); +} +function findHostInstanceWithNoPortals(fiber) { + var hostFiber = findCurrentHostFiberWithNoPortals(fiber); - switch (workInProgressSuspendedReason) { - case SuspendedOnError: { - // Unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - unwindSuspendedUnitOfWork(unitOfWork, thrownValue); - break; - } + if (hostFiber === null) { + return null; + } - case SuspendedOnData: { - var thenable = thrownValue; + return getPublicInstance(hostFiber.stateNode); +} - if (isThenableResolved(thenable)) { - // The data resolved. Try rendering the component again. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - replaySuspendedUnitOfWork(unitOfWork); - break; - } // The work loop is suspended on data. We should wait for it to - // resolve before continuing to render. - // TODO: Handle the case where the promise resolves synchronously. - // Usually this is handled when we instrument the promise to add a - // `status` field, but if the promise already has a status, we won't - // have added a listener until right here. +var shouldErrorImpl = function (fiber) { + return null; +}; - var onResolution = function () { - // Check if the root is still suspended on this promise. - if ( - workInProgressSuspendedReason === SuspendedOnData && - workInProgressRoot === root - ) { - // Mark the root as ready to continue rendering. - workInProgressSuspendedReason = SuspendedAndReadyToContinue; - } // Ensure the root is scheduled. We should do this even if we're - // currently working on a different root, so that we resume - // rendering later. +function shouldError(fiber) { + return shouldErrorImpl(fiber); +} - ensureRootIsScheduled(root, now$1()); - }; +var shouldSuspendImpl = function (fiber) { + return false; +}; - thenable.then(onResolution, onResolution); - break outer; - } +function shouldSuspend(fiber) { + return shouldSuspendImpl(fiber); +} +var overrideHookState = null; +var overrideHookStateDeletePath = null; +var overrideHookStateRenamePath = null; +var overrideProps = null; +var overridePropsDeletePath = null; +var overridePropsRenamePath = null; +var scheduleUpdate = null; +var setErrorHandler = null; +var setSuspenseHandler = null; - case SuspendedOnImmediate: { - // If this fiber just suspended, it's possible the data is already - // cached. Yield to the main thread to give it a chance to ping. If - // it does, we can retry immediately without unwinding the stack. - workInProgressSuspendedReason = SuspendedAndReadyToContinue; - break outer; - } +{ + var copyWithDeleteImpl = function (obj, path, index) { + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); - case SuspendedAndReadyToContinue: { - var _thenable = thrownValue; + if (index + 1 === path.length) { + if (isArray(updated)) { + updated.splice(key, 1); + } else { + delete updated[key]; + } - if (isThenableResolved(_thenable)) { - // The data resolved. Try rendering the component again. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - replaySuspendedUnitOfWork(unitOfWork); - } else { - // Otherwise, unwind then continue with the normal work loop. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - unwindSuspendedUnitOfWork(unitOfWork, thrownValue); - } + return updated; + } // $FlowFixMe number or string is fine here - break; - } + updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); + return updated; + }; - case SuspendedOnDeprecatedThrowPromise: { - // Suspended by an old implementation that uses the `throw promise` - // pattern. The newer replaying behavior can cause subtle issues - // like infinite ping loops. So we maintain the old behavior and - // always unwind. - workInProgressSuspendedReason = NotSuspended; - workInProgressThrownValue = null; - unwindSuspendedUnitOfWork(unitOfWork, thrownValue); - break; - } + var copyWithDelete = function (obj, path) { + return copyWithDeleteImpl(obj, path, 0); + }; - case SuspendedOnHydration: { - // Selective hydration. An update flowed into a dehydrated tree. - // Interrupt the current render so the work loop can switch to the - // hydration lane. - resetWorkInProgressStack(); - workInProgressRootExitStatus = RootDidNotComplete; - break outer; - } + var copyWithRenameImpl = function (obj, oldPath, newPath, index) { + var oldKey = oldPath[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); + + if (index + 1 === oldPath.length) { + var newKey = newPath[index]; // $FlowFixMe number or string is fine here + + updated[newKey] = updated[oldKey]; + + if (isArray(updated)) { + updated.splice(oldKey, 1); + } else { + delete updated[oldKey]; + } + } else { + // $FlowFixMe number or string is fine here + updated[oldKey] = copyWithRenameImpl( + // $FlowFixMe number or string is fine here + obj[oldKey], + oldPath, + newPath, + index + 1 + ); + } + + return updated; + }; + + var copyWithRename = function (obj, oldPath, newPath) { + if (oldPath.length !== newPath.length) { + warn("copyWithRename() expects paths of the same length"); - default: { - throw new Error( - "Unexpected SuspendedReason. This is a bug in React." - ); - } + return; + } else { + for (var i = 0; i < newPath.length - 1; i++) { + if (oldPath[i] !== newPath[i]) { + warn( + "copyWithRename() expects paths to be the same except for the deepest key" + ); + + return; } } + } - if (true && ReactCurrentActQueue.current !== null) { - // `act` special case: If we're inside an `act` scope, don't consult - // `shouldYield`. Always keep working until the render is complete. - // This is not just an optimization: in a unit test environment, we - // can't trust the result of `shouldYield`, because the host I/O is - // likely mocked. - workLoopSync(); - } else { - workLoopConcurrent(); - } + return copyWithRenameImpl(obj, oldPath, newPath, 0); + }; - break; - } catch (thrownValue) { - handleThrow(root, thrownValue); + var copyWithSetImpl = function (obj, path, index, value) { + if (index >= path.length) { + return value; } - } while (true); - resetContextDependencies(); - popDispatcher(prevDispatcher); - popCacheDispatcher(prevCacheDispatcher); - executionContext = prevExecutionContext; + var key = path[index]; + var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe number or string is fine here - { - if (enableDebugTracing) { - logRenderStopped(); + updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); + return updated; + }; + + var copyWithSet = function (obj, path, value) { + return copyWithSetImpl(obj, path, 0, value); + }; + + var findHook = function (fiber, id) { + // For now, the "id" of stateful hooks is just the stateful hook index. + // This may change in the future with e.g. nested hooks. + var currentHook = fiber.memoizedState; + + while (currentHook !== null && id > 0) { + currentHook = currentHook.next; + id--; } - } // Check if the tree has completed. - if (workInProgress !== null) { - // Still work remaining. - if (enableSchedulingProfiler) { - markRenderYielded(); + return currentHook; + }; // Support DevTools editable values for useState and useReducer. + + overrideHookState = function (fiber, id, path, value) { + var hook = findHook(fiber, id); + + if (hook !== null) { + var newState = copyWithSet(hook.memoizedState, path, value); + hook.memoizedState = newState; + hook.baseState = newState; // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. + + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } } + }; - return RootInProgress; - } else { - // Completed the tree. - if (enableSchedulingProfiler) { - markRenderStopped(); - } // Set this to null to indicate there's no in-progress render. + overrideHookStateDeletePath = function (fiber, id, path) { + var hook = findHook(fiber, id); - workInProgressRoot = null; - workInProgressRootRenderLanes = NoLanes; // It's safe to process the queue now that the render phase is complete. + if (hook !== null) { + var newState = copyWithDelete(hook.memoizedState, path); + hook.memoizedState = newState; + hook.baseState = newState; // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. - finishQueueingConcurrentUpdates(); // Return the final exit status. + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - return workInProgressRootExitStatus; - } -} -/** @noinline */ + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + } + }; -function workLoopConcurrent() { - // Perform work until Scheduler asks us to yield - while (workInProgress !== null && !shouldYield()) { - // $FlowFixMe[incompatible-call] found when upgrading Flow - performUnitOfWork(workInProgress); - } -} + overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { + var hook = findHook(fiber, id); -function performUnitOfWork(unitOfWork) { - // 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 = unitOfWork.alternate; - setCurrentFiber(unitOfWork); - var next; + if (hook !== null) { + var newState = copyWithRename(hook.memoizedState, oldPath, newPath); + hook.memoizedState = newState; + hook.baseState = newState; // We aren't actually adding an update to the queue, + // because there is no update we can add for useReducer hooks that won't trigger an error. + // (There's no appropriate action type for DevTools overrides.) + // As a result though, React will see the scheduled update as a noop and bailout. + // Shallow cloning props works as a workaround for now to bypass the bailout check. - if ((unitOfWork.mode & ProfileMode) !== NoMode) { - startProfilerTimer(unitOfWork); - next = beginWork(current, unitOfWork, renderLanes); - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } else { - next = beginWork(current, unitOfWork, renderLanes); - } + fiber.memoizedProps = assign({}, fiber.memoizedProps); + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + } + }; // Support DevTools props for function components, forwardRef, memo, host components, etc. - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; - } + overrideProps = function (fiber, path, value) { + fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); - ReactCurrentOwner$1.current = null; -} + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; + } -function replaySuspendedUnitOfWork(unitOfWork) { - // This is a fork of performUnitOfWork specifcally for replaying a fiber that - // just suspended. - // - var current = unitOfWork.alternate; - setCurrentFiber(unitOfWork); - var next; - setCurrentFiber(unitOfWork); - var isProfilingMode = (unitOfWork.mode & ProfileMode) !== NoMode; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - if (isProfilingMode) { - startProfilerTimer(unitOfWork); - } + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + }; - switch (unitOfWork.tag) { - case IndeterminateComponent: { - // Because it suspended with `use`, we can assume it's a - // function component. - unitOfWork.tag = FunctionComponent; // Fallthrough to the next branch. + overridePropsDeletePath = function (fiber, path) { + fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); + + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; } - // eslint-disable-next-line no-fallthrough - case FunctionComponent: - case ForwardRef: { - // Resolve `defaultProps`. This logic is copied from `beginWork`. - // TODO: Consider moving this switch statement into that module. Also, - // could maybe use this as an opportunity to say `use` doesn't work with - // `defaultProps` :) - var Component = unitOfWork.type; - var unresolvedProps = unitOfWork.pendingProps; - var resolvedProps = - unitOfWork.elementType === Component - ? unresolvedProps - : resolveDefaultProps(Component, unresolvedProps); - next = replayFunctionComponent( - current, - unitOfWork, - resolvedProps, - Component, - workInProgressRootRenderLanes - ); - break; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); } + }; - case SimpleMemoComponent: { - var _Component = unitOfWork.type; - var nextProps = unitOfWork.pendingProps; - next = replayFunctionComponent( - current, - unitOfWork, - nextProps, - _Component, - workInProgressRootRenderLanes - ); - break; + overridePropsRenamePath = function (fiber, oldPath, newPath) { + fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath); + + if (fiber.alternate) { + fiber.alternate.pendingProps = fiber.pendingProps; } - default: { - // Other types besides function components are reset completely before - // being replayed. Currently this only happens when a Usable type is - // reconciled — the reconciler will suspend. - // - // We reset the fiber back to its original state; however, this isn't - // a full "unwind" because we're going to reuse the promises that were - // reconciled previously. So it's intentional that we don't call - // resetSuspendedWorkLoopOnUnwind here. - unwindInterruptedWork(current, unitOfWork); - unitOfWork = workInProgress = resetWorkInProgress( - unitOfWork, - renderLanes - ); - next = beginWork(current, unitOfWork, renderLanes); - break; + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); } - } + }; - if (isProfilingMode) { - stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true); - } // The begin phase finished successfully without suspending. Return to the - // normal work loop. + scheduleUpdate = function (fiber) { + var root = enqueueConcurrentRenderForLane(fiber, SyncLane); - resetCurrentFiber(); - unitOfWork.memoizedProps = unitOfWork.pendingProps; + if (root !== null) { + scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + } + }; - if (next === null) { - // If this doesn't spawn new work, complete the current work. - completeUnitOfWork(unitOfWork); - } else { - workInProgress = next; - } + setErrorHandler = function (newShouldErrorImpl) { + shouldErrorImpl = newShouldErrorImpl; + }; - ReactCurrentOwner$1.current = null; + setSuspenseHandler = function (newShouldSuspendImpl) { + shouldSuspendImpl = newShouldSuspendImpl; + }; } -function unwindSuspendedUnitOfWork(unitOfWork, thrownValue) { - // This is a fork of performUnitOfWork specifcally for unwinding a fiber - // that threw an exception. - // - // Return to the normal work loop. This will unwind the stack, and potentially - // result in showing a fallback. - resetSuspendedWorkLoopOnUnwind(); - var returnFiber = unitOfWork.return; - - if (returnFiber === null || workInProgressRoot === null) { - // Expected to be working on a non-root fiber. This is a fatal error - // because there's no ancestor that can handle it; the root is - // supposed to capture all errors that weren't caught by an error - // boundary. - workInProgressRootExitStatus = RootFatalErrored; - workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next - // sibling, or the parent if there are no siblings. But since the root - // has no siblings nor a parent, we set it to null. Usually this is - // handled by `completeUnitOfWork` or `unwindWork`, but since we're - // intentionally not calling those, we need set it here. - // TODO: Consider calling `unwindWork` to pop the contexts. +function findHostInstanceByFiber(fiber) { + var hostFiber = findCurrentHostFiber(fiber); - workInProgress = null; - return; + if (hostFiber === null) { + return null; } - try { - // Find and mark the nearest Suspense or error boundary that can handle - // this "exception". - throwException( - workInProgressRoot, - returnFiber, - unitOfWork, - thrownValue, - workInProgressRootRenderLanes - ); - } catch (error) { - // We had trouble processing the error. An example of this happening is - // when accessing the `componentDidCatch` property of an error boundary - // throws an error. A weird edge case. There's a regression test for this. - // To prevent an infinite loop, bubble the error up to the next parent. - workInProgress = returnFiber; - throw error; - } // Return to the normal work loop. + return hostFiber.stateNode; +} - completeUnitOfWork(unitOfWork); +function emptyFindFiberByHostInstance(instance) { + return null; } -function completeUnitOfWork(unitOfWork) { - // 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. - var completedWork = unitOfWork; +function getCurrentFiberForDevTools() { + return current; +} - do { - // 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 = completedWork.alternate; - var returnFiber = completedWork.return; // Check if the work completed or if something threw. +function injectIntoDevTools(devToolsConfig) { + var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; + var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; + return injectInternals({ + bundleType: devToolsConfig.bundleType, + version: devToolsConfig.version, + rendererPackageName: devToolsConfig.rendererPackageName, + rendererConfig: devToolsConfig.rendererConfig, + overrideHookState: overrideHookState, + overrideHookStateDeletePath: overrideHookStateDeletePath, + overrideHookStateRenamePath: overrideHookStateRenamePath, + overrideProps: overrideProps, + overridePropsDeletePath: overridePropsDeletePath, + overridePropsRenamePath: overridePropsRenamePath, + setErrorHandler: setErrorHandler, + setSuspenseHandler: setSuspenseHandler, + scheduleUpdate: scheduleUpdate, + currentDispatcherRef: ReactCurrentDispatcher, + findHostInstanceByFiber: findHostInstanceByFiber, + findFiberByHostInstance: + findFiberByHostInstance || emptyFindFiberByHostInstance, + // React Refresh + findHostInstancesForRefresh: findHostInstancesForRefresh, + scheduleRefresh: scheduleRefresh, + scheduleRoot: scheduleRoot, + setRefreshHandler: setRefreshHandler, + // Enables DevTools to append owner stacks to error messages in DEV mode. + getCurrentFiber: getCurrentFiberForDevTools, + // Enables DevTools to detect reconciler version rather than renderer version + // which may not match for third party renderers. + reconcilerVersion: ReactVersion + }); +} - if ((completedWork.flags & Incomplete) === NoFlags$1) { - setCurrentFiber(completedWork); - var next = void 0; +// the renderer. Such as when we're dispatching events or if third party +// libraries need to call batchedUpdates. Eventually, this API will go away when +// everything is batched by default. We'll then have a similar API to opt-out of +// scheduled work and instead do synchronous work. - if ((completedWork.mode & ProfileMode) === NoMode) { - next = completeWork(current, completedWork, renderLanes); - } else { - startProfilerTimer(completedWork); - next = completeWork(current, completedWork, renderLanes); // Update render duration assuming we didn't error. +var isInsideEventHandler = false; - stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); - } +function finishEventHandler() { + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. + var controlledComponentsHavePendingUpdates = needsStateRestore(); - resetCurrentFiber(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + // TODO: Restore state in the microtask, after the discrete updates flush, + // instead of early flushing them here. + flushSync$1(); + restoreStateIfNeeded(); + } +} - if (next !== null) { - // Completing this fiber spawned new work. Work on that next. - workInProgress = next; - return; - } - } else { - // 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(current, completedWork); // Because this fiber did not complete, don't reset its lanes. +function batchedUpdates(fn, a, b) { + if (isInsideEventHandler) { + // If we are currently inside another batch, we need to wait until it + // fully completes before restoring state. + return fn(a, b); + } - if (_next !== null) { - // If completing this work spawned new work, do that next. We'll come - // back here again. - // Since we're restarting, remove anything that is not a host effect - // from the effect tag. - _next.flags &= HostEffectMask; - workInProgress = _next; - return; - } + isInsideEventHandler = true; - if ((completedWork.mode & ProfileMode) !== NoMode) { - // Record the render duration for the fiber that errored. - stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing. + try { + return batchedUpdates$1(fn, a, b); + } finally { + isInsideEventHandler = false; + finishEventHandler(); + } +} // TODO: Replace with flushSync - var actualDuration = completedWork.actualDuration; - var child = completedWork.child; +function isInteractive(tag) { + return ( + tag === "button" || + tag === "input" || + tag === "select" || + tag === "textarea" + ); +} - while (child !== null) { - // $FlowFixMe[unsafe-addition] addition with possible null/undefined value - actualDuration += child.actualDuration; - child = child.sibling; - } +function shouldPreventMouseEvent(name, type, props) { + switch (name) { + case "onClick": + case "onClickCapture": + case "onDoubleClick": + case "onDoubleClickCapture": + case "onMouseDown": + case "onMouseDownCapture": + case "onMouseMove": + case "onMouseMoveCapture": + case "onMouseUp": + case "onMouseUpCapture": + case "onMouseEnter": + return !!(props.disabled && isInteractive(type)); - completedWork.actualDuration = actualDuration; - } + default: + return false; + } +} +/** + * @param {object} inst The instance, which is the source of events. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ - if (returnFiber !== null) { - // Mark the parent fiber as incomplete and clear its subtree flags. - returnFiber.flags |= Incomplete; - returnFiber.subtreeFlags = NoFlags$1; - returnFiber.deletions = null; - } else { - // We've unwound all the way to the root. - workInProgressRootExitStatus = RootDidNotComplete; - workInProgress = null; - return; - } - } +function getListener(inst, registrationName) { + var stateNode = inst.stateNode; - var siblingFiber = completedWork.sibling; + if (stateNode === null) { + // Work in progress (ex: onload events in incremental mode). + return null; + } - if (siblingFiber !== null) { - // If there is more work to do in this returnFiber, do that next. - workInProgress = siblingFiber; - return; - } // Otherwise, return to the parent - // $FlowFixMe[incompatible-type] we bail out when we get a null + var props = getFiberCurrentPropsFromNode(stateNode); - completedWork = returnFiber; // Update the next thing we're working on in case something throws. + if (props === null) { + // Work in progress. + return null; + } - workInProgress = completedWork; - } while (completedWork !== null); // We've reached the root. + var listener = props[registrationName]; - if (workInProgressRootExitStatus === RootInProgress) { - workInProgressRootExitStatus = RootCompleted; + if (shouldPreventMouseEvent(registrationName, inst.type, props)) { + return null; + } + + if (listener && typeof listener !== "function") { + throw new Error( + "Expected `" + + registrationName + + "` listener to be a function, instead got a value of `" + + typeof listener + + "` type." + ); } + + return listener; } -function commitRoot(root, recoverableErrors, transitions) { - // TODO: This no longer makes any sense. We already wrap the mutation and - // layout phases. Should be able to remove. - var previousUpdateLanePriority = getCurrentUpdatePriority$1(); - var prevTransition = ReactCurrentBatchConfig.transition; +var passiveBrowserEventsSupported = false; // Check if browser support events with passive listeners +// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support +if (canUseDOM) { try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(DiscreteEventPriority); - commitRootImpl( - root, - recoverableErrors, - transitions, - previousUpdateLanePriority - ); - } finally { - ReactCurrentBatchConfig.transition = prevTransition; - setCurrentUpdatePriority(previousUpdateLanePriority); + var options = {}; + Object.defineProperty(options, "passive", { + get: function () { + passiveBrowserEventsSupported = true; + } + }); + window.addEventListener("test", options, options); + window.removeEventListener("test", options, options); + } catch (e) { + passiveBrowserEventsSupported = false; } - - return null; } -function commitRootImpl( - root, - recoverableErrors, - transitions, - renderPriorityLevel +var EventListenerWWW = require("EventListener"); + +function addEventBubbleListener(target, eventType, listener) { + return EventListenerWWW.listen(target, eventType, listener); +} +function addEventCaptureListener(target, eventType, listener) { + return EventListenerWWW.capture(target, eventType, listener); +} +function addEventCaptureListenerWithPassiveFlag( + target, + eventType, + listener, + passive ) { - do { - // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which - // means `flushPassiveEffects` will sometimes result in additional - // passive effects. So we need to keep flushing in a loop until there are - // no more pending effects. - // TODO: Might be better if `flushPassiveEffects` did not automatically - // flush synchronous work at the end, to avoid factoring hazards like this. - flushPassiveEffects(); - } while (rootWithPendingPassiveEffects !== null); + return EventListenerWWW.captureWithPassiveFlag( + target, + eventType, + listener, + passive + ); +} +function addEventBubbleListenerWithPassiveFlag( + target, + eventType, + listener, + passive +) { + return EventListenerWWW.bubbleWithPassiveFlag( + target, + eventType, + listener, + passive + ); +} +function removeEventListener(target, eventType, listener, capture) { + listener.remove(); +} // Flow magic to verify the exports of this file match the original version. - flushRenderPhaseStrictModeWarningsInDEV(); +/** + * These variables store information about text content of a target node, + * allowing comparison of content before and after a given event. + * + * Identify the node where selection currently begins, then observe + * both its text content and its current position in the DOM. Since the + * browser may natively replace the target node during composition, we can + * use its position to find its replacement. + * + * + */ +var root = null; +var startText = null; +var fallbackText = null; +function initialize(nativeEventTarget) { + root = nativeEventTarget; + startText = getText(); + return true; +} +function reset() { + root = null; + startText = null; + fallbackText = null; +} +function getData() { + if (fallbackText) { + return fallbackText; + } - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Should not already be working."); + var start; + var startValue = startText; + var startLength = startValue.length; + var end; + var endValue = getText(); + var endLength = endValue.length; + + for (start = 0; start < startLength; start++) { + if (startValue[start] !== endValue[start]) { + break; + } } - var finishedWork = root.finishedWork; - var lanes = root.finishedLanes; + var minEnd = startLength - start; - { - if (enableDebugTracing) { - logCommitStarted(lanes); + for (end = 1; end <= minEnd; end++) { + if (startValue[startLength - end] !== endValue[endLength - end]) { + break; } } - if (enableSchedulingProfiler) { - markCommitStarted(lanes); + var sliceTail = end > 1 ? 1 - end : undefined; + fallbackText = endValue.slice(start, sliceTail); + return fallbackText; +} +function getText() { + if ("value" in root) { + return root.value; } - if (finishedWork === null) { - { - if (enableDebugTracing) { - logCommitStopped(); - } - } + return root.textContent; +} - if (enableSchedulingProfiler) { - markCommitStopped(); - } +/** + * `charCode` represents the actual "character code" and is safe to use with + * `String.fromCharCode`. As such, only keys that correspond to printable + * characters produce a valid `charCode`, the only exception to this is Enter. + * The Tab-key is considered non-printable and does not have a `charCode`, + * presumably because it does not produce a tab-character in browsers. + * + * @param {object} nativeEvent Native browser event. + * @return {number} Normalized `charCode` property. + */ +function getEventCharCode(nativeEvent) { + var charCode; + var keyCode = nativeEvent.keyCode; - return null; - } else { - { - if (lanes === NoLanes) { - error( - "root.finishedLanes should not be empty during a commit. This is a " + - "bug in React." - ); - } - } - } + if ("charCode" in nativeEvent) { + charCode = nativeEvent.charCode; // FF does not set `charCode` for the Enter-key, check against `keyCode`. - root.finishedWork = null; - root.finishedLanes = NoLanes; + if (charCode === 0 && keyCode === 13) { + charCode = 13; + } + } else { + // IE8 does not implement `charCode`, but `keyCode` has the correct value. + charCode = keyCode; + } // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux) + // report Enter as charCode 10 when ctrl is pressed. - if (finishedWork === root.current) { - throw new Error( - "Cannot commit the same tree as before. This error is likely caused by " + - "a bug in React. Please file an issue." - ); - } // commitRoot never returns a continuation; it always finishes synchronously. - // So we can clear these now to allow a new callback to be scheduled. + if (charCode === 10) { + charCode = 13; + } // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. + // Must not discard the (non-)printable Enter-key. - root.callbackNode = null; - root.callbackPriority = NoLane; // Check which lanes no longer have any work scheduled on them, and mark - // those as finished. + if (charCode >= 32 || charCode === 13) { + return charCode; + } - var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes); // Make sure to account for lanes that were updated by a concurrent event - // during the render phase; don't mark them as finished. + return 0; +} - var concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes(); - remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes); - markRootFinished(root, remainingLanes); +function functionThatReturnsTrue() { + return true; +} - if (root === workInProgressRoot) { - // We can reset these now that they are finished. - workInProgressRoot = null; - workInProgress = null; - workInProgressRootRenderLanes = NoLanes; - } // If there are pending passive effects, schedule a callback to process them. - // Do this as early as possible, so it is queued before anything else that - // might get scheduled in the commit phase. (See #16714.) - // TODO: Delete all other places that schedule the passive effect callback - // They're redundant. +function functionThatReturnsFalse() { + return false; +} // This is intentionally a factory so that we have different returned constructors. +// If we had a single constructor, it would be megamorphic and engines would deopt. - if ( - (finishedWork.subtreeFlags & PassiveMask) !== NoFlags$1 || - (finishedWork.flags & PassiveMask) !== NoFlags$1 +function createSyntheticEvent(Interface) { + /** + * Synthetic events are dispatched by event plugins, typically in response to a + * top-level event delegation handler. + * + * These systems should generally use pooling to reduce the frequency of garbage + * collection. The system should check `isPersistent` to determine whether the + * event should be released into the pool after being dispatched. Users that + * need a persisted event should invoke `persist`. + * + * Synthetic events (and subclasses) implement the DOM Level 3 Events API by + * normalizing browser quirks. Subclasses do not necessarily have to implement a + * DOM interface; custom application-specific events can also subclass this. + */ + // $FlowFixMe[missing-this-annot] + function SyntheticBaseEvent( + reactName, + reactEventType, + targetInst, + nativeEvent, + nativeEventTarget ) { - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - pendingPassiveEffectsRemainingLanes = remainingLanes; // workInProgressTransitions might be overwritten, so we want - // to store it in pendingPassiveTransitions until they get processed - // We need to pass this through as an argument to commitRoot - // because workInProgressTransitions might have changed between - // the previous render and commit if we throttle the commit - // with setTimeout + this._reactName = reactName; + this._targetInst = targetInst; + this.type = reactEventType; + this.nativeEvent = nativeEvent; + this.target = nativeEventTarget; + this.currentTarget = null; - pendingPassiveTransitions = transitions; - scheduleCallback(NormalPriority$1, function () { - flushPassiveEffects(); // This render triggered passive effects: release the root cache pool - // *after* passive effects fire to avoid freeing a cache pool that may - // be referenced by a node in the tree (HostRoot, Cache boundary etc) + for (var propName in Interface) { + if (!Interface.hasOwnProperty(propName)) { + continue; + } - return null; - }); + var normalize = Interface[propName]; + + if (normalize) { + this[propName] = normalize(nativeEvent); + } else { + this[propName] = nativeEvent[propName]; + } } - } // Check if there are any effects in the whole tree. - // TODO: This is left over from the effect list implementation, where we had - // to check for the existence of `firstEffect` to satisfy Flow. I think the - // only other reason this optimization exists is because it affects profiling. - // Reconsider whether this is necessary. - var subtreeHasEffects = - (finishedWork.subtreeFlags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; - var rootHasEffect = - (finishedWork.flags & - (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== - NoFlags$1; + var defaultPrevented = + nativeEvent.defaultPrevented != null + ? nativeEvent.defaultPrevented + : nativeEvent.returnValue === false; - if (subtreeHasEffects || rootHasEffect) { - var prevTransition = ReactCurrentBatchConfig.transition; - ReactCurrentBatchConfig.transition = null; - var previousPriority = getCurrentUpdatePriority$1(); - setCurrentUpdatePriority(DiscreteEventPriority); - var prevExecutionContext = executionContext; - executionContext |= CommitContext; // Reset this to null before calling lifecycles + if (defaultPrevented) { + this.isDefaultPrevented = functionThatReturnsTrue; + } else { + this.isDefaultPrevented = functionThatReturnsFalse; + } - ReactCurrentOwner$1.current = null; // The commit phase is broken into several sub-phases. We do a separate pass - // of the effect list for each phase: all mutation effects come before all - // layout effects, and so on. - // The first phase a "before mutation" phase. We use this phase to read the - // state of the host tree right before we mutate it. This is where - // getSnapshotBeforeUpdate is called. + this.isPropagationStopped = functionThatReturnsFalse; + return this; + } // $FlowFixMe[prop-missing] found when upgrading Flow - var shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects( - root, - finishedWork - ); + assign(SyntheticBaseEvent.prototype, { + // $FlowFixMe[missing-this-annot] + preventDefault: function () { + this.defaultPrevented = true; + var event = this.nativeEvent; - { - // Mark the current commit time to be shared by all Profilers in this - // batch. This enables them to be grouped later. - recordCommitTime(); - } + if (!event) { + return; + } - if (enableProfilerNestedUpdateScheduledHook) { - // Track the root here, rather than in commitLayoutEffects(), because of ref setters. - // Updates scheduled during ref detachment should also be flagged. - rootCommittingMutationOrLayoutEffects = root; - } // The next phase is the mutation phase, where we mutate the host tree. + if (event.preventDefault) { + event.preventDefault(); // $FlowFixMe - flow is not aware of `unknown` in IE + } else if (typeof event.returnValue !== "unknown") { + event.returnValue = false; + } - commitMutationEffects(root, finishedWork, lanes); + this.isDefaultPrevented = functionThatReturnsTrue; + }, + // $FlowFixMe[missing-this-annot] + stopPropagation: function () { + var event = this.nativeEvent; - { - if (shouldFireAfterActiveInstanceBlur) { - afterActiveInstanceBlur(); + if (!event) { + return; } - } - resetAfterCommit(); // The work-in-progress tree is now the current tree. This must come after - // the mutation phase, so that the previous tree is still current during - // componentWillUnmount, but before the layout phase, so that the finished - // work is current during componentDidMount/Update. + if (event.stopPropagation) { + event.stopPropagation(); // $FlowFixMe - flow is not aware of `unknown` in IE + } else if (typeof event.cancelBubble !== "unknown") { + // The ChangeEventPlugin registers a "propertychange" event for + // IE. This event does not support bubbling or cancelling, and + // any references to cancelBubble throw "Member not found". A + // typeof check of "unknown" circumvents this issue (and is also + // IE specific). + event.cancelBubble = true; + } - root.current = finishedWork; // The next phase is the layout phase, where we call effects that read - // the host tree after it's been mutated. The idiomatic use case for this is - // layout, but class component lifecycles also fire here for legacy reasons. + this.isPropagationStopped = functionThatReturnsTrue; + }, - { - if (enableDebugTracing) { - logLayoutEffectsStarted(lanes); - } - } + /** + * We release all dispatched `SyntheticEvent`s after each event loop, adding + * them back into the pool. This allows a way to hold onto a reference that + * won't be added back into the pool. + */ + persist: function () { + // Modern event system doesn't use pooling. + }, - if (enableSchedulingProfiler) { - markLayoutEffectsStarted(lanes); - } + /** + * Checks if this event should be released back into the pool. + * + * @return {boolean} True if this should not be released, false otherwise. + */ + isPersistent: functionThatReturnsTrue + }); + return SyntheticBaseEvent; +} +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ - commitLayoutEffects(finishedWork, root, lanes); +var EventInterface = { + eventPhase: 0, + bubbles: 0, + cancelable: 0, + timeStamp: function (event) { + return event.timeStamp || Date.now(); + }, + defaultPrevented: 0, + isTrusted: 0 +}; +var SyntheticEvent = createSyntheticEvent(EventInterface); - { - if (enableDebugTracing) { - logLayoutEffectsStopped(); - } - } +var UIEventInterface = assign({}, EventInterface, { + view: 0, + detail: 0 +}); - if (enableSchedulingProfiler) { - markLayoutEffectsStopped(); - } +var SyntheticUIEvent = createSyntheticEvent(UIEventInterface); +var lastMovementX; +var lastMovementY; +var lastMouseEvent; - if (enableProfilerNestedUpdateScheduledHook) { - rootCommittingMutationOrLayoutEffects = null; - } // Tell Scheduler to yield at the end of the frame, so the browser has an - // opportunity to paint. +function updateMouseMovementPolyfillState(event) { + if (event !== lastMouseEvent) { + if (lastMouseEvent && event.type === "mousemove") { + // $FlowFixMe assuming this is a number + lastMovementX = event.screenX - lastMouseEvent.screenX; // $FlowFixMe assuming this is a number - requestPaint(); - executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value. + lastMovementY = event.screenY - lastMouseEvent.screenY; + } else { + lastMovementX = 0; + lastMovementY = 0; + } - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; - } else { - // No effects. - root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were - // no effects. - // TODO: Maybe there's a better way to report this. + lastMouseEvent = event; + } +} +/** + * @interface MouseEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ - { - recordCommitTime(); +var MouseEventInterface = assign({}, UIEventInterface, { + screenX: 0, + screenY: 0, + clientX: 0, + clientY: 0, + pageX: 0, + pageY: 0, + ctrlKey: 0, + shiftKey: 0, + altKey: 0, + metaKey: 0, + getModifierState: getEventModifierState, + button: 0, + buttons: 0, + relatedTarget: function (event) { + if (event.relatedTarget === undefined) + return event.fromElement === event.srcElement + ? event.toElement + : event.fromElement; + return event.relatedTarget; + }, + movementX: function (event) { + if ("movementX" in event) { + return event.movementX; } + + updateMouseMovementPolyfillState(event); + return lastMovementX; + }, + movementY: function (event) { + if ("movementY" in event) { + return event.movementY; + } // Don't need to call updateMouseMovementPolyfillState() here + // because it's guaranteed to have already run when movementX + // was copied. + + return lastMovementY; } +}); - var rootDidHavePassiveEffects = rootDoesHavePassiveEffects; +var SyntheticMouseEvent = createSyntheticEvent(MouseEventInterface); +/** + * @interface DragEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ - if (rootDoesHavePassiveEffects) { - // This commit has passive effects. Stash a reference to them. But don't - // schedule a callback until after flushing layout work. - rootDoesHavePassiveEffects = false; - rootWithPendingPassiveEffects = root; - pendingPassiveEffectsLanes = lanes; - } else { - // There were no passive effects, so we can immediately release the cache - // pool for this render. - releaseRootPooledCache(root, remainingLanes); +var DragEventInterface = assign({}, MouseEventInterface, { + dataTransfer: 0 +}); - { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; - } - } // Read this again, since an effect might have updated it +var SyntheticDragEvent = createSyntheticEvent(DragEventInterface); +/** + * @interface FocusEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ - remainingLanes = root.pendingLanes; // Check if there's remaining work on this root - // TODO: This is part of the `componentDidCatch` implementation. Its purpose - // is to detect whether something might have called setState inside - // `componentDidCatch`. The mechanism is known to be flawed because `setState` - // inside `componentDidCatch` is itself flawed — that's why we recommend - // `getDerivedStateFromError` instead. However, it could be improved by - // checking if remainingLanes includes Sync work, instead of whether there's - // any work remaining at all (which would also include stuff like Suspense - // retries or transitions). It's been like this for a while, though, so fixing - // it probably isn't that urgent. +var FocusEventInterface = assign({}, UIEventInterface, { + relatedTarget: 0 +}); - if (remainingLanes === NoLanes) { - // If there's no remaining work, we can clear the set of already failed - // error boundaries. - legacyErrorBoundariesThatAlreadyFailed = null; - } +var SyntheticFocusEvent = createSyntheticEvent(FocusEventInterface); +/** + * @interface Event + * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface + * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent + */ - { - if (!rootDidHavePassiveEffects) { - commitDoubleInvokeEffectsInDEV(root, false); - } - } +var AnimationEventInterface = assign({}, EventInterface, { + animationName: 0, + elapsedTime: 0, + pseudoElement: 0 +}); - onCommitRoot$1(finishedWork.stateNode, renderPriorityLevel); +var SyntheticAnimationEvent = createSyntheticEvent(AnimationEventInterface); +/** + * @interface Event + * @see http://www.w3.org/TR/clipboard-apis/ + */ - { - if (isDevToolsPresent) { - root.memoizedUpdaters.clear(); - } +var ClipboardEventInterface = assign({}, EventInterface, { + clipboardData: function (event) { + return "clipboardData" in event + ? event.clipboardData + : window.clipboardData; } +}); - { - onCommitRoot(); - } // Always call this before exiting `commitRoot`, to ensure that any - // additional work on this root is scheduled. - - ensureRootIsScheduled(root, now$1()); +var SyntheticClipboardEvent = createSyntheticEvent(ClipboardEventInterface); +/** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents + */ - if (recoverableErrors !== null) { - // There were errors during this render, but recovered from them without - // needing to surface it to the UI. We log them here. - var onRecoverableError = root.onRecoverableError; +var CompositionEventInterface = assign({}, EventInterface, { + data: 0 +}); - for (var i = 0; i < recoverableErrors.length; i++) { - var recoverableError = recoverableErrors[i]; - var errorInfo = makeErrorInfo( - recoverableError.digest, - recoverableError.stack - ); - onRecoverableError(recoverableError.value, errorInfo); - } - } +var SyntheticCompositionEvent = createSyntheticEvent(CompositionEventInterface); +/** + * @interface Event + * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 + * /#events-inputevents + */ +// Happens to share the same list for now. - if (hasUncaughtError) { - hasUncaughtError = false; - var error$1 = firstUncaughtError; - firstUncaughtError = null; - throw error$1; - } // If the passive effects are the result of a discrete render, flush them - // synchronously at the end of the current task so that the result is - // immediately observable. Otherwise, we assume that they are not - // order-dependent and do not need to be observed by external systems, so we - // can wait until after paint. - // TODO: We can optimize this by not scheduling the callback earlier. Since we - // currently schedule the callback in multiple places, will wait until those - // are consolidated. +var SyntheticInputEvent = SyntheticCompositionEvent; +/** + * Normalization of deprecated HTML5 `key` values + * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names + */ - if (includesSyncLane(pendingPassiveEffectsLanes) && root.tag !== LegacyRoot) { - flushPassiveEffects(); - } // Read this again, since a passive effect might have updated it +var normalizeKey = { + Esc: "Escape", + Spacebar: " ", + Left: "ArrowLeft", + Up: "ArrowUp", + Right: "ArrowRight", + Down: "ArrowDown", + Del: "Delete", + Win: "OS", + Menu: "ContextMenu", + Apps: "ContextMenu", + Scroll: "ScrollLock", + MozPrintableKey: "Unidentified" +}; +/** + * Translation from legacy `keyCode` to HTML5 `key` + * Only special keys supported, all others depend on keyboard layout or browser + * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names + */ - remainingLanes = root.pendingLanes; +var translateToKey = { + "8": "Backspace", + "9": "Tab", + "12": "Clear", + "13": "Enter", + "16": "Shift", + "17": "Control", + "18": "Alt", + "19": "Pause", + "20": "CapsLock", + "27": "Escape", + "32": " ", + "33": "PageUp", + "34": "PageDown", + "35": "End", + "36": "Home", + "37": "ArrowLeft", + "38": "ArrowUp", + "39": "ArrowRight", + "40": "ArrowDown", + "45": "Insert", + "46": "Delete", + "112": "F1", + "113": "F2", + "114": "F3", + "115": "F4", + "116": "F5", + "117": "F6", + "118": "F7", + "119": "F8", + "120": "F9", + "121": "F10", + "122": "F11", + "123": "F12", + "144": "NumLock", + "145": "ScrollLock", + "224": "Meta" +}; +/** + * @param {object} nativeEvent Native browser event. + * @return {string} Normalized `key` property. + */ - if (includesSyncLane(remainingLanes)) { - { - markNestedUpdateScheduled(); - } // Count the number of times the root synchronously re-renders without - // finishing. If there are too many, it indicates an infinite update loop. +function getEventKey(nativeEvent) { + if (nativeEvent.key) { + // Normalize inconsistent values reported by browsers due to + // implementations of a working draft specification. + // FireFox implements `key` but returns `MozPrintableKey` for all + // printable characters (normalized to `Unidentified`), ignore it. + var key = normalizeKey[nativeEvent.key] || nativeEvent.key; // $FlowFixMe unable to index with a `mixed` value - if (root === rootWithNestedUpdates) { - nestedUpdateCount++; - } else { - nestedUpdateCount = 0; - rootWithNestedUpdates = root; + if (key !== "Unidentified") { + return key; } - } else { - nestedUpdateCount = 0; - } // If layout work was scheduled, flush it now. + } // Browser does not implement `key`, polyfill as much of it as we can. - flushSyncCallbacks(); + if (nativeEvent.type === "keypress") { + var charCode = getEventCharCode( + // $FlowFixMe unable to narrow to `KeyboardEvent` + nativeEvent + ); // The enter-key is technically both printable and non-printable and can + // thus be captured by `keypress`, no other non-printable key should. - { - if (enableDebugTracing) { - logCommitStopped(); - } + return charCode === 13 ? "Enter" : String.fromCharCode(charCode); } - if (enableSchedulingProfiler) { - markCommitStopped(); + if (nativeEvent.type === "keydown" || nativeEvent.type === "keyup") { + // While user keyboard layout determines the actual meaning of each + // `keyCode` value, almost all function keys have a universal value. + // $FlowFixMe unable to index with a `mixed` value + return translateToKey[nativeEvent.keyCode] || "Unidentified"; } - if (enableTransitionTracing) { - // We process transitions during passive effects. However, passive effects can be - // processed synchronously during the commit phase as well as asynchronously after - // paint. At the end of the commit phase, we schedule a callback that will be called - // after the next paint. If the transitions have already been processed (passive - // effect phase happened synchronously), we will schedule a callback to process - // the transitions. However, if we don't have any pending transition callbacks, this - // means that the transitions have yet to be processed (passive effects processed after paint) - // so we will store the end time of paint so that we can process the transitions - // and then call the callback via the correct end time. - var prevRootTransitionCallbacks = root.transitionCallbacks; + return ""; +} +/** + * Translation from modifier key to the associated property in the event. + * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers + */ - if (prevRootTransitionCallbacks !== null) { - schedulePostPaintCallback(function (endTime) { - var prevPendingTransitionCallbacks = currentPendingTransitionCallbacks; +var modifierKeyToProp = { + Alt: "altKey", + Control: "ctrlKey", + Meta: "metaKey", + Shift: "shiftKey" +}; // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support +// getModifierState. If getModifierState is not supported, we map it to a set of +// modifier keys exposed by the event. In this case, Lock-keys are not supported. +// $FlowFixMe[missing-local-annot] +// $FlowFixMe[missing-this-annot] - if (prevPendingTransitionCallbacks !== null) { - currentPendingTransitionCallbacks = null; - scheduleCallback(IdlePriority, function () { - processTransitionCallbacks( - prevPendingTransitionCallbacks, - endTime, - prevRootTransitionCallbacks - ); - }); - } else { - currentEndTime = endTime; - } - }); - } +function modifierStateGetter(keyArg) { + var syntheticEvent = this; + var nativeEvent = syntheticEvent.nativeEvent; + + if (nativeEvent.getModifierState) { + return nativeEvent.getModifierState(keyArg); } - return null; + var keyProp = modifierKeyToProp[keyArg]; + return keyProp ? !!nativeEvent[keyProp] : false; } -function makeErrorInfo(digest, componentStack) { - { - var errorInfo = { - componentStack: componentStack, - digest: digest - }; - Object.defineProperty(errorInfo, "digest", { - configurable: false, - enumerable: true, - get: function () { - error( - 'You are accessing "digest" from the errorInfo object passed to onRecoverableError.' + - " This property is deprecated and will be removed in a future version of React." + - " To access the digest of an Error look for this property on the Error instance itself." - ); - - return digest; - } - }); - return errorInfo; - } +function getEventModifierState(nativeEvent) { + return modifierStateGetter; } +/** + * @interface KeyboardEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ -function releaseRootPooledCache(root, remainingLanes) { - { - var pooledCacheLanes = (root.pooledCacheLanes &= remainingLanes); +var KeyboardEventInterface = assign({}, UIEventInterface, { + key: getEventKey, + code: 0, + location: 0, + ctrlKey: 0, + shiftKey: 0, + altKey: 0, + metaKey: 0, + repeat: 0, + locale: 0, + getModifierState: getEventModifierState, + // Legacy Interface + charCode: function (event) { + // `charCode` is the result of a KeyPress event and represents the value of + // the actual printable character. + // KeyPress is deprecated, but its replacement is not yet final and not + // implemented in any major browser. Only KeyPress has charCode. + if (event.type === "keypress") { + return getEventCharCode( + // $FlowFixMe unable to narrow to `KeyboardEvent` + event + ); + } - if (pooledCacheLanes === NoLanes) { - // None of the remaining work relies on the cache pool. Clear it so - // subsequent requests get a new cache - var pooledCache = root.pooledCache; + return 0; + }, + keyCode: function (event) { + // `keyCode` is the result of a KeyDown/Up event and represents the value of + // physical keyboard key. + // The actual meaning of the value depends on the users' keyboard layout + // which cannot be detected. Assuming that it is a US keyboard layout + // provides a surprisingly accurate mapping for US and European users. + // Due to this, it is left to the user to implement at this time. + if (event.type === "keydown" || event.type === "keyup") { + return event.keyCode; + } - if (pooledCache != null) { - root.pooledCache = null; - releaseCache(pooledCache); - } + return 0; + }, + which: function (event) { + // `which` is an alias for either `keyCode` or `charCode` depending on the + // type of the event. + if (event.type === "keypress") { + return getEventCharCode( + // $FlowFixMe unable to narrow to `KeyboardEvent` + event + ); + } + + if (event.type === "keydown" || event.type === "keyup") { + return event.keyCode; } + + return 0; } -} +}); -function flushPassiveEffects() { - // Returns whether passive effects were flushed. - // TODO: Combine this check with the one in flushPassiveEFfectsImpl. We should - // probably just combine the two functions. I believe they were only separate - // in the first place because we used to wrap it with - // `Scheduler.runWithPriority`, which accepts a function. But now we track the - // priority within React itself, so we can mutate the variable directly. - if (rootWithPendingPassiveEffects !== null) { - // Cache the root since rootWithPendingPassiveEffects is cleared in - // flushPassiveEffectsImpl - var root = rootWithPendingPassiveEffects; // Cache and clear the remaining lanes flag; it must be reset since this - // method can be called from various places, not always from commitRoot - // where the remaining lanes are known +var SyntheticKeyboardEvent = createSyntheticEvent(KeyboardEventInterface); +/** + * @interface PointerEvent + * @see http://www.w3.org/TR/pointerevents/ + */ - var remainingLanes = pendingPassiveEffectsRemainingLanes; - pendingPassiveEffectsRemainingLanes = NoLanes; - var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes); - var priority = lowerEventPriority(DefaultEventPriority, renderPriority); - var prevTransition = ReactCurrentBatchConfig.transition; - var previousPriority = getCurrentUpdatePriority$1(); +var PointerEventInterface = assign({}, MouseEventInterface, { + pointerId: 0, + width: 0, + height: 0, + pressure: 0, + tangentialPressure: 0, + tiltX: 0, + tiltY: 0, + twist: 0, + pointerType: 0, + isPrimary: 0 +}); - try { - ReactCurrentBatchConfig.transition = null; - setCurrentUpdatePriority(priority); - return flushPassiveEffectsImpl(); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig.transition = prevTransition; // Once passive effects have run for the tree - giving components a - // chance to retain cache instances they use - release the pooled - // cache at the root (if there is one) +var SyntheticPointerEvent = createSyntheticEvent(PointerEventInterface); +/** + * @interface TouchEvent + * @see http://www.w3.org/TR/touch-events/ + */ - releaseRootPooledCache(root, remainingLanes); - } - } +var TouchEventInterface = assign({}, UIEventInterface, { + touches: 0, + targetTouches: 0, + changedTouches: 0, + altKey: 0, + metaKey: 0, + ctrlKey: 0, + shiftKey: 0, + getModifierState: getEventModifierState +}); - return false; -} -function enqueuePendingPassiveProfilerEffect(fiber) { - { - pendingPassiveProfilerEffects.push(fiber); +var SyntheticTouchEvent = createSyntheticEvent(TouchEventInterface); +/** + * @interface Event + * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- + * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent + */ - if (!rootDoesHavePassiveEffects) { - rootDoesHavePassiveEffects = true; - scheduleCallback(NormalPriority$1, function () { - flushPassiveEffects(); - return null; - }); - } - } -} +var TransitionEventInterface = assign({}, EventInterface, { + propertyName: 0, + elapsedTime: 0, + pseudoElement: 0 +}); -function flushPassiveEffectsImpl() { - if (rootWithPendingPassiveEffects === null) { - return false; - } // Cache and clear the transitions flag +var SyntheticTransitionEvent = createSyntheticEvent(TransitionEventInterface); +/** + * @interface WheelEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ + +var WheelEventInterface = assign({}, MouseEventInterface, { + deltaX: function (event) { + return "deltaX" in event + ? event.deltaX // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). + : "wheelDeltaX" in event // $FlowFixMe assuming this is a number + ? -event.wheelDeltaX + : 0; + }, + deltaY: function (event) { + return "deltaY" in event + ? event.deltaY // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). + : "wheelDeltaY" in event // $FlowFixMe assuming this is a number + ? -event.wheelDeltaY // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). + : "wheelDelta" in event // $FlowFixMe assuming this is a number + ? -event.wheelDelta + : 0; + }, + deltaZ: 0, + // Browsers without "deltaMode" is reporting in raw wheel delta where one + // notch on the scroll is always +/- 120, roughly equivalent to pixels. + // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or + // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. + deltaMode: 0 +}); - var transitions = pendingPassiveTransitions; - pendingPassiveTransitions = null; - var root = rootWithPendingPassiveEffects; - var lanes = pendingPassiveEffectsLanes; - rootWithPendingPassiveEffects = null; // TODO: This is sometimes out of sync with rootWithPendingPassiveEffects. - // Figure out why and fix it. It's not causing any known issues (probably - // because it's only used for profiling), but it's a refactor hazard. +var SyntheticWheelEvent = createSyntheticEvent(WheelEventInterface); - pendingPassiveEffectsLanes = NoLanes; +var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space - if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { - throw new Error("Cannot flush passive effects while already rendering."); - } +var START_KEYCODE = 229; +var canUseCompositionEvent = canUseDOM && "CompositionEvent" in window; +var documentMode = null; - { - isFlushingPassiveEffects = true; - didScheduleUpdateDuringPassiveEffects = false; +if (canUseDOM && "documentMode" in document) { + documentMode = document.documentMode; +} // Webkit offers a very useful `textInput` event that can be used to +// directly represent `beforeInput`. The IE `textinput` event is not as +// useful, so we don't use it. - if (enableDebugTracing) { - logPassiveEffectsStarted(lanes); - } - } +var canUseTextInputEvent = canUseDOM && "TextEvent" in window && !documentMode; // In IE9+, we have access to composition events, but the data supplied +// by the native compositionend event may be incorrect. Japanese ideographic +// spaces, for instance (\u3000) are not recorded correctly. - if (enableSchedulingProfiler) { - markPassiveEffectsStarted(lanes); - } +var useFallbackCompositionData = + canUseDOM && + (!canUseCompositionEvent || + (documentMode && documentMode > 8 && documentMode <= 11)); +var SPACEBAR_CODE = 32; +var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); - var prevExecutionContext = executionContext; - executionContext |= CommitContext; - commitPassiveUnmountEffects(root.current); - commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects +function registerEvents$3() { + registerTwoPhaseEvent("onBeforeInput", [ + "compositionend", + "keypress", + "textInput", + "paste" + ]); + registerTwoPhaseEvent("onCompositionEnd", [ + "compositionend", + "focusout", + "keydown", + "keypress", + "keyup", + "mousedown" + ]); + registerTwoPhaseEvent("onCompositionStart", [ + "compositionstart", + "focusout", + "keydown", + "keypress", + "keyup", + "mousedown" + ]); + registerTwoPhaseEvent("onCompositionUpdate", [ + "compositionupdate", + "focusout", + "keydown", + "keypress", + "keyup", + "mousedown" + ]); +} // Track whether we've ever handled a keypress on the space key. - { - var profilerEffects = pendingPassiveProfilerEffects; - pendingPassiveProfilerEffects = []; +var hasSpaceKeypress = false; +/** + * Return whether a native keypress event is assumed to be a command. + * This is required because Firefox fires `keypress` events for key commands + * (cut, copy, select-all, etc.) even though no character is inserted. + */ - for (var i = 0; i < profilerEffects.length; i++) { - var fiber = profilerEffects[i]; - commitPassiveEffectDurations(root, fiber); - } - } +function isKeypressCommand(nativeEvent) { + return ( + (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && // ctrlKey && altKey is equivalent to AltGr, and is not a command. + !(nativeEvent.ctrlKey && nativeEvent.altKey) + ); +} +/** + * Translate native top level events into event types. + */ - { - if (enableDebugTracing) { - logPassiveEffectsStopped(); - } - } +function getCompositionEventType(domEventName) { + switch (domEventName) { + case "compositionstart": + return "onCompositionStart"; - if (enableSchedulingProfiler) { - markPassiveEffectsStopped(); - } + case "compositionend": + return "onCompositionEnd"; - { - commitDoubleInvokeEffectsInDEV(root, true); + case "compositionupdate": + return "onCompositionUpdate"; } +} +/** + * Does our fallback best-guess model think this event signifies that + * composition has begun? + */ - executionContext = prevExecutionContext; - flushSyncCallbacks(); - - if (enableTransitionTracing) { - var prevPendingTransitionCallbacks = currentPendingTransitionCallbacks; - var prevRootTransitionCallbacks = root.transitionCallbacks; - var prevEndTime = currentEndTime; - - if ( - prevPendingTransitionCallbacks !== null && - prevRootTransitionCallbacks !== null && - prevEndTime !== null - ) { - currentPendingTransitionCallbacks = null; - currentEndTime = null; - scheduleCallback(IdlePriority, function () { - processTransitionCallbacks( - prevPendingTransitionCallbacks, - prevEndTime, - prevRootTransitionCallbacks - ); - }); - } - } +function isFallbackCompositionStart(domEventName, nativeEvent) { + return domEventName === "keydown" && nativeEvent.keyCode === START_KEYCODE; +} +/** + * Does our fallback mode think that this event is the end of composition? + */ - { - // If additional passive effects were scheduled, increment a counter. If this - // exceeds the limit, we'll fire a warning. - if (didScheduleUpdateDuringPassiveEffects) { - if (root === rootWithPassiveNestedUpdates) { - nestedPassiveUpdateCount++; - } else { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = root; - } - } else { - nestedPassiveUpdateCount = 0; - } +function isFallbackCompositionEnd(domEventName, nativeEvent) { + switch (domEventName) { + case "keyup": + // Command keys insert or clear IME input. + return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; - isFlushingPassiveEffects = false; - didScheduleUpdateDuringPassiveEffects = false; - } // TODO: Move to commitPassiveMountEffects + case "keydown": + // Expect IME keyCode on each keydown. If we get any other + // code we must have exited earlier. + return nativeEvent.keyCode !== START_KEYCODE; - onPostCommitRoot(root); + case "keypress": + case "mousedown": + case "focusout": + // Events are not possible without cancelling IME. + return true; - { - var stateNode = root.current.stateNode; - stateNode.effectDuration = 0; - stateNode.passiveEffectDuration = 0; + default: + return false; } - - return true; } +/** + * Google Input Tools provides composition data via a CustomEvent, + * with the `data` property populated in the `detail` object. If this + * is available on the event object, use it. If not, this is a plain + * composition event and we have nothing special to extract. + * + * @param {object} nativeEvent + * @return {?string} + */ -function isAlreadyFailedLegacyErrorBoundary(instance) { - return ( - legacyErrorBoundariesThatAlreadyFailed !== null && - legacyErrorBoundariesThatAlreadyFailed.has(instance) - ); -} -function markLegacyErrorBoundaryAsFailed(instance) { - if (legacyErrorBoundariesThatAlreadyFailed === null) { - legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); - } else { - legacyErrorBoundariesThatAlreadyFailed.add(instance); - } -} +function getDataFromCustomEvent(nativeEvent) { + var detail = nativeEvent.detail; -function prepareToThrowUncaughtError(error) { - if (!hasUncaughtError) { - hasUncaughtError = true; - firstUncaughtError = error; + if (typeof detail === "object" && "data" in detail) { + return detail.data; } + + return null; } +/** + * Check if a composition event was triggered by Korean IME. + * Our fallback mode does not work well with IE's Korean IME, + * so just use native composition events when Korean IME is used. + * Although CompositionEvent.locale property is deprecated, + * it is available in IE, where our fallback mode is enabled. + * + * @param {object} nativeEvent + * @return {boolean} + */ -var onUncaughtError = prepareToThrowUncaughtError; +function isUsingKoreanIME(nativeEvent) { + return nativeEvent.locale === "ko"; +} // Track the current IME composition status, if any. -function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) { - var errorInfo = createCapturedValueAtFiber(error, sourceFiber); - var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane); - var root = enqueueUpdate(rootFiber, update, SyncLane); - var eventTime = requestEventTime(); +var isComposing = false; +/** + * @return {?object} A SyntheticCompositionEvent. + */ - if (root !== null) { - markRootUpdated(root, SyncLane, eventTime); - ensureRootIsScheduled(root, eventTime); - } -} +function extractCompositionEvent( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget +) { + var eventType; + var fallbackData; -function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error$1) { - { - reportUncaughtErrorInDEV(error$1); - setIsRunningInsertionEffect(false); + if (canUseCompositionEvent) { + eventType = getCompositionEventType(domEventName); + } else if (!isComposing) { + if (isFallbackCompositionStart(domEventName, nativeEvent)) { + eventType = "onCompositionStart"; + } + } else if (isFallbackCompositionEnd(domEventName, nativeEvent)) { + eventType = "onCompositionEnd"; } - if (sourceFiber.tag === HostRoot) { - // Error was thrown at the root. There is no parent, so the root - // itself should capture it. - captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error$1); - return; + if (!eventType) { + return null; } - var fiber = null; - - if (skipUnmountedBoundaries) { - fiber = nearestMountedAncestor; - } else { - fiber = sourceFiber.return; + if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { + // The current composition is stored statically and must not be + // overwritten while composition continues. + if (!isComposing && eventType === "onCompositionStart") { + isComposing = initialize(nativeEventTarget); + } else if (eventType === "onCompositionEnd") { + if (isComposing) { + fallbackData = getData(); + } + } } - while (fiber !== null) { - if (fiber.tag === HostRoot) { - captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error$1); - return; - } else if (fiber.tag === ClassComponent) { - var ctor = fiber.type; - var instance = fiber.stateNode; + var listeners = accumulateTwoPhaseListeners(targetInst, eventType); - if ( - typeof ctor.getDerivedStateFromError === "function" || - (typeof instance.componentDidCatch === "function" && - !isAlreadyFailedLegacyErrorBoundary(instance)) - ) { - var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber); - var update = createClassErrorUpdate(fiber, errorInfo, SyncLane); - var root = enqueueUpdate(fiber, update, SyncLane); - var eventTime = requestEventTime(); + if (listeners.length > 0) { + var event = new SyntheticCompositionEvent( + eventType, + domEventName, + null, + nativeEvent, + nativeEventTarget + ); + dispatchQueue.push({ + event: event, + listeners: listeners + }); - if (root !== null) { - markRootUpdated(root, SyncLane, eventTime); - ensureRootIsScheduled(root, eventTime); - } + if (fallbackData) { + // Inject data generated from fallback path into the synthetic event. + // This matches the property of native CompositionEventInterface. + // $FlowFixMe[incompatible-use] + event.data = fallbackData; + } else { + var customData = getDataFromCustomEvent(nativeEvent); - return; + if (customData !== null) { + // $FlowFixMe[incompatible-use] + event.data = customData; } } - - fiber = fiber.return; - } - - { - // TODO: Until we re-land skipUnmountedBoundaries (see #20147), this warning - // will fire for errors that are thrown by destroy functions inside deleted - // trees. What it should instead do is propagate the error to the parent of - // the deleted tree. In the meantime, do not add this warning to the - // allowlist; this is only for our internal use. - error( - "Internal React error: Attempted to capture a commit phase error " + - "inside a detached tree. This indicates a bug in React. Likely " + - "causes include deleting the same fiber more than once, committing an " + - "already-finished tree, or an inconsistent return pointer.\n\n" + - "Error message:\n\n%s", - error$1 - ); } } -function attachPingListener(root, wakeable, lanes) { - // Attach a ping listener - // - // The data might resolve before we have a chance to commit the fallback. Or, - // in the case of a refresh, we'll never commit a fallback. So we need to - // attach a listener now. When it resolves ("pings"), we can decide whether to - // try rendering the tree again. - // - // Only attach a listener if one does not already exist for the lanes - // we're currently rendering (which acts like a "thread ID" here). - // - // We only need to do this in concurrent mode. Legacy Suspense always - // commits fallbacks synchronously, so there are no pings. - var pingCache = root.pingCache; - var threadIDs; - if (pingCache === null) { - pingCache = root.pingCache = new PossiblyWeakMap(); - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } else { - threadIDs = pingCache.get(wakeable); +function getNativeBeforeInputChars(domEventName, nativeEvent) { + switch (domEventName) { + case "compositionend": + return getDataFromCustomEvent(nativeEvent); - if (threadIDs === undefined) { - threadIDs = new Set(); - pingCache.set(wakeable, threadIDs); - } - } + case "keypress": + /** + * If native `textInput` events are available, our goal is to make + * use of them. However, there is a special case: the spacebar key. + * In Webkit, preventing default on a spacebar `textInput` event + * cancels character insertion, but it *also* causes the browser + * to fall back to its default spacebar behavior of scrolling the + * page. + * + * Tracking at: + * https://code.google.com/p/chromium/issues/detail?id=355103 + * + * To avoid this issue, use the keypress event as if no `textInput` + * event is available. + */ + var which = nativeEvent.which; - if (!threadIDs.has(lanes)) { - workInProgressRootDidAttachPingListener = true; // Memoize using the thread ID to prevent redundant listeners. + if (which !== SPACEBAR_CODE) { + return null; + } - threadIDs.add(lanes); - var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes); + hasSpaceKeypress = true; + return SPACEBAR_CHAR; - { - if (isDevToolsPresent) { - // If we have pending work still, restore the original updaters - restorePendingUpdaters(root, lanes); + case "textInput": + // Record the characters to be added to the DOM. + var chars = nativeEvent.data; // If it's a spacebar character, assume that we have already handled + // it at the keypress level and bail immediately. Android Chrome + // doesn't give us keycodes, so we need to ignore it. + + if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { + return null; } - } - wakeable.then(ping, ping); + return chars; + + default: + // For other native event types, do nothing. + return null; } } +/** + * For browsers that do not provide the `textInput` event, extract the + * appropriate string to use for SyntheticInputEvent. + */ -function pingSuspendedRoot(root, wakeable, pingedLanes) { - var pingCache = root.pingCache; +function getFallbackBeforeInputChars(domEventName, nativeEvent) { + // If we are currently composing (IME) and using a fallback to do so, + // try to extract the composed characters from the fallback object. + // If composition event is available, we extract a string only at + // compositionevent, otherwise extract it at fallback events. + if (isComposing) { + if ( + domEventName === "compositionend" || + (!canUseCompositionEvent && + isFallbackCompositionEnd(domEventName, nativeEvent)) + ) { + var chars = getData(); + reset(); + isComposing = false; + return chars; + } - if (pingCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - pingCache.delete(wakeable); + return null; } - var eventTime = requestEventTime(); - markRootPinged(root, pingedLanes); - warnIfSuspenseResolutionNotWrappedWithActDEV(root); + switch (domEventName) { + case "paste": + // If a paste event occurs after a keypress, throw out the input + // chars. Paste events should not lead to BeforeInput events. + return null; - if ( - workInProgressRoot === root && - isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes) - ) { - // Received a ping at the same priority level at which we're currently - // rendering. We might want to restart this render. This should mirror - // the logic of whether or not a root suspends once it completes. - // TODO: If we're rendering sync either due to Sync, Batched or expired, - // we should probably never restart. - // If we're suspended with delay, or if it's a retry, we'll always suspend - // so we can always restart. - if ( - workInProgressRootExitStatus === RootSuspendedWithDelay || - (workInProgressRootExitStatus === RootSuspended && - includesOnlyRetries(workInProgressRootRenderLanes) && - now$1() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) - ) { - // Force a restart from the root by unwinding the stack. Unless this is - // being called from the render phase, because that would cause a crash. - if ((executionContext & RenderContext) === NoContext) { - prepareFreshStack(root, NoLanes); + case "keypress": + /** + * As of v27, Firefox may fire keypress events even when no character + * will be inserted. A few possibilities: + * + * - `which` is `0`. Arrow keys, Esc key, etc. + * + * - `which` is the pressed key code, but no char is available. + * Ex: 'AltGr + d` in Polish. There is no modified character for + * this key combination and no character is inserted into the + * document, but FF fires the keypress for char code `100` anyway. + * No `input` event will occur. + * + * - `which` is the pressed key code, but a command combination is + * being used. Ex: `Cmd+C`. No character is inserted, and no + * `input` event will occur. + */ + if (!isKeypressCommand(nativeEvent)) { + // IE fires the `keypress` event when a user types an emoji via + // Touch keyboard of Windows. In such a case, the `char` property + // holds an emoji character like `\uD83D\uDE0A`. Because its length + // is 2, the property `which` does not represent an emoji correctly. + // In such a case, we directly return the `char` property instead of + // using `which`. + if (nativeEvent.char && nativeEvent.char.length > 1) { + return nativeEvent.char; + } else if (nativeEvent.which) { + return String.fromCharCode(nativeEvent.which); + } } - } else { - // Even though we can't restart right now, we might get an - // opportunity later. So we mark this render as having a ping. - workInProgressRootPingedLanes = mergeLanes( - workInProgressRootPingedLanes, - pingedLanes - ); - } - } - ensureRootIsScheduled(root, eventTime); -} - -function retryTimedOutBoundary(boundaryFiber, retryLane) { - // The boundary fiber (a Suspense component or SuspenseList component) - // previously 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 rendering again, at a new lanes. - if (retryLane === NoLane) { - // TODO: Assign this to `suspenseState.retryLane`? to avoid - // unnecessary entanglement? - retryLane = requestRetryLane(boundaryFiber); - } // TODO: Special case idle priority? + return null; - var eventTime = requestEventTime(); - var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane); + case "compositionend": + return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) + ? null + : nativeEvent.data; - if (root !== null) { - markRootUpdated(root, retryLane, eventTime); - ensureRootIsScheduled(root, eventTime); + default: + return null; } } +/** + * Extract a SyntheticInputEvent for `beforeInput`, based on either native + * `textInput` or fallback behavior. + * + * @return {?object} A SyntheticInputEvent. + */ -function retryDehydratedSuspenseBoundary(boundaryFiber) { - var suspenseState = boundaryFiber.memoizedState; - var retryLane = NoLane; +function extractBeforeInputEvent( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget +) { + var chars; - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + if (canUseTextInputEvent) { + chars = getNativeBeforeInputChars(domEventName, nativeEvent); + } else { + chars = getFallbackBeforeInputChars(domEventName, nativeEvent); + } // If no characters are being inserted, no BeforeInput event should + // be fired. - retryTimedOutBoundary(boundaryFiber, retryLane); -} -function resolveRetryWakeable(boundaryFiber, wakeable) { - var retryLane = NoLane; // Default + if (!chars) { + return null; + } - var retryCache; + var listeners = accumulateTwoPhaseListeners(targetInst, "onBeforeInput"); - switch (boundaryFiber.tag) { - case SuspenseComponent: - retryCache = boundaryFiber.stateNode; - var suspenseState = boundaryFiber.memoizedState; + if (listeners.length > 0) { + var event = new SyntheticInputEvent( + "onBeforeInput", + "beforeinput", + null, + nativeEvent, + nativeEventTarget + ); + dispatchQueue.push({ + event: event, + listeners: listeners + }); // $FlowFixMe[incompatible-use] - if (suspenseState !== null) { - retryLane = suspenseState.retryLane; - } + event.data = chars; + } +} +/** + * Create an `onBeforeInput` event to match + * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. + * + * This event plugin is based on the native `textInput` event + * available in Chrome, Safari, Opera, and IE. This event fires after + * `onKeyPress` and `onCompositionEnd`, but before `onInput`. + * + * `beforeInput` is spec'd but not implemented in any browsers, and + * the `input` event does not provide any useful information about what has + * actually been added, contrary to the spec. Thus, `textInput` is the best + * available event to identify the characters that have actually been inserted + * into the target node. + * + * This plugin is also responsible for emitting `composition` events, thus + * allowing us to share composition fallback code for both `beforeInput` and + * `composition` event types. + */ - break; +function extractEvents$5( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer +) { + extractCompositionEvent( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget + ); + extractBeforeInputEvent( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget + ); +} - case SuspenseListComponent: - retryCache = boundaryFiber.stateNode; - break; +/** + * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + */ +var supportedInputTypes = { + color: true, + date: true, + datetime: true, + "datetime-local": true, + email: true, + month: true, + number: true, + password: true, + range: true, + search: true, + tel: true, + text: true, + time: true, + url: true, + week: true +}; - case OffscreenComponent: { - var instance = boundaryFiber.stateNode; - retryCache = instance._retryCache; - break; - } +function isTextInputElement(elem) { + var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); - default: - throw new Error( - "Pinged unknown suspense boundary type. " + - "This is probably a bug in React." - ); + if (nodeName === "input") { + return !!supportedInputTypes[elem.type]; } - if (retryCache !== null) { - // The wakeable resolved, so we no longer need to memoize, because it will - // never be thrown again. - retryCache.delete(wakeable); + if (nodeName === "textarea") { + return true; } - retryTimedOutBoundary(boundaryFiber, retryLane); -} // Computes the next Just Noticeable Difference (JND) boundary. -// The theory is that a person can't tell the difference between small differences in time. -// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable -// difference in the experience. However, waiting for longer might mean that we can avoid -// showing an intermediate loading state. The longer we have already waited, the harder it -// is to tell small differences in time. Therefore, the longer we've already waited, -// the longer we can wait additionally. At some point we have to give up though. -// We pick a train model where the next boundary commits at a consistent schedule. -// These particular numbers are vague estimates. We expect to adjust them based on research. - -function jnd(timeElapsed) { - return timeElapsed < 120 - ? 120 - : timeElapsed < 480 - ? 480 - : timeElapsed < 1080 - ? 1080 - : timeElapsed < 1920 - ? 1920 - : timeElapsed < 3000 - ? 3000 - : timeElapsed < 4320 - ? 4320 - : ceil(timeElapsed / 1960) * 1960; + return false; } -function throwIfInfiniteUpdateLoopDetected() { - if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { - nestedUpdateCount = 0; - nestedPassiveUpdateCount = 0; - rootWithNestedUpdates = null; - rootWithPassiveNestedUpdates = null; - throw new Error( - "Maximum update depth exceeded. This can happen when a component " + - "repeatedly calls setState inside componentWillUpdate or " + - "componentDidUpdate. React limits the number of nested updates to " + - "prevent infinite loops." - ); +/** + * Checks if an event is supported in the current execution environment. + * + * NOTE: This will not work correctly for non-generic events such as `change`, + * `reset`, `load`, `error`, and `select`. + * + * Borrows from Modernizr. + * + * @param {string} eventNameSuffix Event name, e.g. "click". + * @return {boolean} True if the event is supported. + * @internal + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ + +function isEventSupported(eventNameSuffix) { + if (!canUseDOM) { + return false; } - { - if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) { - nestedPassiveUpdateCount = 0; - rootWithPassiveNestedUpdates = null; + var eventName = "on" + eventNameSuffix; + var isSupported = eventName in document; - error( - "Maximum update depth exceeded. This can happen when a component " + - "calls setState inside useEffect, but useEffect either doesn't " + - "have a dependency array, or one of the dependencies changes on " + - "every render." - ); - } + if (!isSupported) { + var element = document.createElement("div"); + element.setAttribute(eventName, "return;"); + isSupported = typeof element[eventName] === "function"; } -} -function flushRenderPhaseStrictModeWarningsInDEV() { - { - ReactStrictModeWarnings.flushLegacyContextWarning(); - ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings(); - } + return isSupported; } -function commitDoubleInvokeEffectsInDEV(root, hasPassiveEffects) { - { - { - legacyCommitDoubleInvokeEffectsInDEV(root.current, hasPassiveEffects); - } - } +function registerEvents$2() { + registerTwoPhaseEvent("onChange", [ + "change", + "click", + "focusin", + "focusout", + "input", + "keydown", + "keyup", + "selectionchange" + ]); } -function legacyCommitDoubleInvokeEffectsInDEV(fiber, hasPassiveEffects) { - // TODO (StrictEffects) Should we set a marker on the root if it contains strict effects - // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level. - // Maybe not a big deal since this is DEV only behavior. - setCurrentFiber(fiber); - invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV); +function createAndAccumulateChangeEvent( + dispatchQueue, + inst, + nativeEvent, + target +) { + // Flag this event loop as needing state restore. + enqueueStateRestore(target); + var listeners = accumulateTwoPhaseListeners(inst, "onChange"); - if (hasPassiveEffects) { - invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV); + if (listeners.length > 0) { + var event = new SyntheticEvent( + "onChange", + "change", + null, + nativeEvent, + target + ); + dispatchQueue.push({ + event: event, + listeners: listeners + }); } +} +/** + * For IE shims + */ - invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV); - - if (hasPassiveEffects) { - invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV); - } +var activeElement$1 = null; +var activeElementInst$1 = null; +/** + * SECTION: handle `change` event + */ - resetCurrentFiber(); +function shouldUseChangeEvent(elem) { + var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); + return ( + nodeName === "select" || (nodeName === "input" && elem.type === "file") + ); } -function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) { - var current = firstChild; - var subtreeRoot = null; +function manualDispatchChangeEvent(nativeEvent) { + var dispatchQueue = []; + createAndAccumulateChangeEvent( + dispatchQueue, + activeElementInst$1, + nativeEvent, + getEventTarget(nativeEvent) + ); // If change and propertychange bubbled, we'd just bind to it like all the + // other events and have it go through ReactBrowserEventEmitter. Since it + // doesn't, we manually listen for the events and so we have to enqueue and + // process the abstract event manually. + // + // Batching is necessary here in order to ensure that all event handlers run + // before the next rerender (including event handlers attached to ancestor + // elements instead of directly on the input). Without this, controlled + // components don't work properly in conjunction with event bubbling because + // the component is rerendered and the value reverted before all the event + // handlers can run. See https://github.com/facebook/react/issues/708. - while (current != null) { - var primarySubtreeFlag = current.subtreeFlags & fiberFlags; + batchedUpdates(runEventInBatch, dispatchQueue); +} - if ( - current !== subtreeRoot && - current.child != null && - primarySubtreeFlag !== NoFlags$1 - ) { - current = current.child; - } else { - if ((current.flags & fiberFlags) !== NoFlags$1) { - invokeEffectFn(current); - } +function runEventInBatch(dispatchQueue) { + processDispatchQueue(dispatchQueue, 0); +} - if (current.sibling !== null) { - current = current.sibling; - } else { - current = subtreeRoot = current.return; - } - } +function getInstIfValueChanged(targetInst) { + var targetNode = getNodeFromInstance(targetInst); + + if (updateValueIfChanged(targetNode)) { + return targetInst; } } -var didWarnStateUpdateForNotYetMountedComponent = null; -function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) { - { - if ((executionContext & RenderContext) !== NoContext) { - // We let the other warning about render phase updates deal with this one. - return; - } +function getTargetInstForChangeEvent(domEventName, targetInst) { + if (domEventName === "change") { + return targetInst; + } +} +/** + * SECTION: handle `input` event + */ - if (!(fiber.mode & ConcurrentMode)) { - return; - } +var isInputEventSupported = false; - var tag = fiber.tag; +if (canUseDOM) { + // IE9 claims to support the input event but fails to trigger it when + // deleting text, so we ignore its input events. + isInputEventSupported = + isEventSupported("input") && + (!document.documentMode || document.documentMode > 9); +} +/** + * (For IE <=9) Starts tracking propertychange events on the passed-in element + * and override the value property so that we can distinguish user events from + * value changes in JS. + */ - if ( - tag !== IndeterminateComponent && - tag !== HostRoot && - tag !== ClassComponent && - tag !== FunctionComponent && - tag !== ForwardRef && - tag !== MemoComponent && - tag !== SimpleMemoComponent - ) { - // Only warn for user-defined components, not internal ones like Suspense. - return; - } // We show the whole stack but dedupe on the top component's name because - // the problematic code almost always lies inside that component. +function startWatchingForValueChange(target, targetInst) { + activeElement$1 = target; + activeElementInst$1 = targetInst; + activeElement$1.attachEvent("onpropertychange", handlePropertyChange); +} +/** + * (For IE <=9) Removes the event listeners from the currently-tracked element, + * if any exists. + */ - var componentName = getComponentNameFromFiber(fiber) || "ReactComponent"; +function stopWatchingForValueChange() { + if (!activeElement$1) { + return; + } - if (didWarnStateUpdateForNotYetMountedComponent !== null) { - if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) { - return; - } // $FlowFixMe[incompatible-use] found when upgrading Flow + activeElement$1.detachEvent("onpropertychange", handlePropertyChange); + activeElement$1 = null; + activeElementInst$1 = null; +} +/** + * (For IE <=9) Handles a propertychange event, sending a `change` event if + * the value of the active element has changed. + */ +// $FlowFixMe[missing-local-annot] - didWarnStateUpdateForNotYetMountedComponent.add(componentName); - } else { - didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]); - } +function handlePropertyChange(nativeEvent) { + if (nativeEvent.propertyName !== "value") { + return; + } - var previousFiber = current; + if (getInstIfValueChanged(activeElementInst$1)) { + manualDispatchChangeEvent(nativeEvent); + } +} - try { - setCurrentFiber(fiber); +function handleEventsForInputEventPolyfill(domEventName, target, targetInst) { + if (domEventName === "focusin") { + // In IE9, propertychange fires for most input events but is buggy and + // doesn't fire when text is deleted, but conveniently, selectionchange + // appears to fire in all of the remaining cases so we catch those and + // forward the event if the value has changed + // In either case, we don't want to call the event handler if the value + // is changed from JS so we redefine a setter for `.value` that updates + // our activeElementValue variable, allowing us to ignore those changes + // + // stopWatching() should be a noop here but we call it just in case we + // missed a blur event somehow. + stopWatchingForValueChange(); + startWatchingForValueChange(target, targetInst); + } else if (domEventName === "focusout") { + stopWatchingForValueChange(); + } +} // For IE8 and IE9. - error( - "Can't perform a React state update on a component that hasn't mounted yet. " + - "This indicates that you have a side-effect in your render function that " + - "asynchronously later calls tries to update the component. Move this work to " + - "useEffect instead." - ); - } finally { - if (previousFiber) { - setCurrentFiber(fiber); - } else { - resetCurrentFiber(); - } - } +function getTargetInstForInputEventPolyfill(domEventName, targetInst) { + if ( + domEventName === "selectionchange" || + domEventName === "keyup" || + domEventName === "keydown" + ) { + // On the selectionchange event, the target is just document which isn't + // helpful for us so just check activeElement instead. + // + // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire + // propertychange on the first input event after setting `value` from a + // script and fires only keydown, keypress, keyup. Catching keyup usually + // gets it and catching keydown lets us fire an event for the first + // keystroke if user does a key repeat (it'll be a little delayed: right + // before the second keystroke). Other input methods (e.g., paste) seem to + // fire selectionchange normally. + return getInstIfValueChanged(activeElementInst$1); } } -var beginWork; +/** + * SECTION: handle `click` event + */ -if (replayFailedUnitOfWorkWithInvokeGuardedCallback) { - var dummyFiber = null; +function shouldUseClickEvent(elem) { + // Use the `click` event to detect changes to checkbox and radio inputs. + // This approach works across all browsers, whereas `change` does not fire + // until `blur` in IE8. + var nodeName = elem.nodeName; + return ( + nodeName && + nodeName.toLowerCase() === "input" && + (elem.type === "checkbox" || elem.type === "radio") + ); +} - beginWork = function (current, unitOfWork, lanes) { - // If a component throws an error, we replay it again in a synchronously - // dispatched event, so that the debugger will treat it as an uncaught - // error See ReactErrorUtils for more information. - // Before entering the begin phase, copy the work-in-progress onto a dummy - // fiber. If beginWork throws, we'll use this to reset the state. - var originalWorkInProgressCopy = assignFiberPropertiesInDEV( - dummyFiber, - unitOfWork - ); +function getTargetInstForClickEvent(domEventName, targetInst) { + if (domEventName === "click") { + return getInstIfValueChanged(targetInst); + } +} - try { - return beginWork$1(current, unitOfWork, lanes); - } catch (originalError) { - if ( - didSuspendOrErrorWhileHydratingDEV() || - originalError === SuspenseException || - originalError === SelectiveHydrationException || - (originalError !== null && - typeof originalError === "object" && - typeof originalError.then === "function") - ) { - // Don't replay promises. - // Don't replay errors if we are hydrating and have already suspended or handled an error - throw originalError; - } // Don't reset current debug fiber, since we're about to work on the - // same fiber again. - // Unwind the failed stack frame +function getTargetInstForInputOrChangeEvent(domEventName, targetInst) { + if (domEventName === "input" || domEventName === "change") { + return getInstIfValueChanged(targetInst); + } +} - resetSuspendedWorkLoopOnUnwind(); - unwindInterruptedWork(current, unitOfWork); // Restore the original properties of the fiber. +function handleControlledInputBlur(node) { + var state = node._wrapperState; - assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy); + if (!state || !state.controlled || node.type !== "number") { + return; + } - if (unitOfWork.mode & ProfileMode) { - // Reset the profiler timer. - startProfilerTimer(unitOfWork); - } // Run beginWork again. + if (!disableInputAttributeSyncing) { + // If controlled, assign the value attribute to the current value on blur + setDefaultValue(node, "number", node.value); + } +} +/** + * This plugin creates an `onChange` event that normalizes change events + * across form elements. This event fires at a time when it's possible to + * change the element's value without seeing a flicker. + * + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - select + */ - invokeGuardedCallback( - null, - beginWork$1, - null, - current, - unitOfWork, - lanes - ); +function extractEvents$4( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer +) { + var targetNode = targetInst ? getNodeFromInstance(targetInst) : window; + var getTargetInstFunc, handleEventFunc; - if (hasCaughtError()) { - var replayError = clearCaughtError(); + if (shouldUseChangeEvent(targetNode)) { + getTargetInstFunc = getTargetInstForChangeEvent; + } else if (isTextInputElement(targetNode)) { + if (isInputEventSupported) { + getTargetInstFunc = getTargetInstForInputOrChangeEvent; + } else { + getTargetInstFunc = getTargetInstForInputEventPolyfill; + handleEventFunc = handleEventsForInputEventPolyfill; + } + } else if (shouldUseClickEvent(targetNode)) { + getTargetInstFunc = getTargetInstForClickEvent; + } else if ( + enableCustomElementPropertySupport && + targetInst && + isCustomComponent(targetInst.elementType, targetInst.memoizedProps) + ) { + getTargetInstFunc = getTargetInstForChangeEvent; + } - if ( - typeof replayError === "object" && - replayError !== null && - replayError._suppressLogging && - typeof originalError === "object" && - originalError !== null && - !originalError._suppressLogging - ) { - // If suppressed, let the flag carry over to the original error which is the one we'll rethrow. - originalError._suppressLogging = true; - } - } // We always throw the original error in case the second render pass is not idempotent. - // This can happen if a memoized function or CommonJS module doesn't throw after first invocation. + if (getTargetInstFunc) { + var inst = getTargetInstFunc(domEventName, targetInst); - throw originalError; + if (inst) { + createAndAccumulateChangeEvent( + dispatchQueue, + inst, + nativeEvent, + nativeEventTarget + ); + return; } - }; -} else { - beginWork = beginWork$1; -} + } -var didWarnAboutUpdateInRender = false; -var didWarnAboutUpdateInRenderForAnotherComponent; + if (handleEventFunc) { + handleEventFunc(domEventName, targetNode, targetInst); + } // When blurring, set the value attribute for number inputs -{ - didWarnAboutUpdateInRenderForAnotherComponent = new Set(); + if (domEventName === "focusout") { + handleControlledInputBlur(targetNode); + } } -function warnAboutRenderPhaseUpdatesInDEV(fiber) { - { - if (isRendering) { - switch (fiber.tag) { - case FunctionComponent: - case ForwardRef: - case SimpleMemoComponent: { - var renderingComponentName = - (workInProgress && getComponentNameFromFiber(workInProgress)) || - "Unknown"; // Dedupe by the rendering component because it's the one that needs to be fixed. - - var dedupeKey = renderingComponentName; - - if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) { - didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey); - var setStateComponentName = - getComponentNameFromFiber(fiber) || "Unknown"; - - error( - "Cannot update a component (`%s`) while rendering a " + - "different component (`%s`). To locate the bad setState() call inside `%s`, " + - "follow the stack trace as described in https://reactjs.org/link/setstate-in-render", - setStateComponentName, - renderingComponentName, - renderingComponentName - ); - } - - break; - } +function registerEvents$1() { + registerDirectEvent("onMouseEnter", ["mouseout", "mouseover"]); + registerDirectEvent("onMouseLeave", ["mouseout", "mouseover"]); + registerDirectEvent("onPointerEnter", ["pointerout", "pointerover"]); + registerDirectEvent("onPointerLeave", ["pointerout", "pointerover"]); +} +/** + * For almost every interaction we care about, there will be both a top-level + * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that + * we do not extract duplicate events. However, moving the mouse into the + * browser from outside will not fire a `mouseout` event. In this case, we use + * the `mouseover` top-level event. + */ - case ClassComponent: { - if (!didWarnAboutUpdateInRender) { - error( - "Cannot update during an existing state transition (such as " + - "within `render`). Render methods should be a pure " + - "function of props and state." - ); +function extractEvents$3( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer +) { + var isOverEvent = + domEventName === "mouseover" || domEventName === "pointerover"; + var isOutEvent = domEventName === "mouseout" || domEventName === "pointerout"; - didWarnAboutUpdateInRender = true; - } + if (isOverEvent && !isReplayingEvent(nativeEvent)) { + // If this is an over event with a target, we might have already dispatched + // the event in the out event of the other target. If this is replayed, + // then it's because we couldn't dispatch against this target previously + // so we have to do it now instead. + var related = nativeEvent.relatedTarget || nativeEvent.fromElement; - break; - } + if (related) { + // If the related node is managed by React, we can assume that we have + // already dispatched the corresponding events during its mouseout. + if ( + getClosestInstanceFromNode(related) || + isContainerMarkedAsRoot(related) + ) { + return; } } } -} -function restorePendingUpdaters(root, lanes) { - { - if (isDevToolsPresent) { - var memoizedUpdaters = root.memoizedUpdaters; - memoizedUpdaters.forEach(function (schedulingFiber) { - addFiberToLanesMap(root, schedulingFiber, lanes); - }); // This function intentionally does not clear memoized updaters. - // Those may still be relevant to the current commit - // and a future one (e.g. Suspense). - } + if (!isOutEvent && !isOverEvent) { + // Must not be a mouse or pointer in or out - ignoring. + return; } -} -var fakeActCallbackNode = {}; // $FlowFixMe[missing-local-annot] -function scheduleCallback(priorityLevel, callback) { - { - // If we're currently inside an `act` scope, bypass Scheduler and push to - // the `act` queue instead. - var actQueue = ReactCurrentActQueue.current; + var win; // TODO: why is this nullable in the types but we read from it? - if (actQueue !== null) { - actQueue.push(callback); - return fakeActCallbackNode; + if (nativeEventTarget.window === nativeEventTarget) { + // `nativeEventTarget` is probably a window object. + win = nativeEventTarget; + } else { + // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. + var doc = nativeEventTarget.ownerDocument; + + if (doc) { + win = doc.defaultView || doc.parentWindow; } else { - return scheduleCallback$2(priorityLevel, callback); + win = window; } } -} - -function cancelCallback(callbackNode) { - if (callbackNode === fakeActCallbackNode) { - return; - } // In production, always call Scheduler. This function will be stripped out. - return cancelCallback$1(callbackNode); -} + var from; + var to; -function shouldForceFlushFallbacksInDEV() { - // Never force flush in production. This function should get stripped out. - return ReactCurrentActQueue.current !== null; -} + if (isOutEvent) { + var _related = nativeEvent.relatedTarget || nativeEvent.toElement; -function warnIfUpdatesNotWrappedWithActDEV(fiber) { - { - if (fiber.mode & ConcurrentMode) { - if (!isConcurrentActEnvironment()) { - // Not in an act environment. No need to warn. - return; - } - } else { - // Legacy mode has additional cases where we suppress a warning. - if (!isLegacyActEnvironment()) { - // Not in an act environment. No need to warn. - return; - } + from = targetInst; + to = _related ? getClosestInstanceFromNode(_related) : null; - if (executionContext !== NoContext) { - // Legacy mode doesn't warn if the update is batched, i.e. - // batchedUpdates or flushSync. - return; - } + if (to !== null) { + var nearestMounted = getNearestMountedFiber(to); + var tag = to.tag; if ( - fiber.tag !== FunctionComponent && - fiber.tag !== ForwardRef && - fiber.tag !== SimpleMemoComponent + to !== nearestMounted || + (tag !== HostComponent && tag !== HostSingleton && tag !== HostText) ) { - // For backwards compatibility with pre-hooks code, legacy mode only - // warns for updates that originate from a hook. - return; + to = null; } } + } else { + // Moving to a node from outside the window. + from = null; + to = targetInst; + } - if (ReactCurrentActQueue.current === null) { - var previousFiber = current; + if (from === to) { + // Nothing pertains to our managed components. + return; + } - try { - setCurrentFiber(fiber); + var SyntheticEventCtor = SyntheticMouseEvent; + var leaveEventType = "onMouseLeave"; + var enterEventType = "onMouseEnter"; + var eventTypePrefix = "mouse"; - error( - "An update to %s inside a test was not wrapped in act(...).\n\n" + - "When testing, code that causes React state updates should be " + - "wrapped into act(...):\n\n" + - "act(() => {\n" + - " /* fire events that update state */\n" + - "});\n" + - "/* assert on the output */\n\n" + - "This ensures that you're testing the behavior the user would see " + - "in the browser." + - " Learn more at https://reactjs.org/link/wrap-tests-with-act", - getComponentNameFromFiber(fiber) - ); - } finally { - if (previousFiber) { - setCurrentFiber(fiber); - } else { - resetCurrentFiber(); - } - } - } + if (domEventName === "pointerout" || domEventName === "pointerover") { + SyntheticEventCtor = SyntheticPointerEvent; + leaveEventType = "onPointerLeave"; + enterEventType = "onPointerEnter"; + eventTypePrefix = "pointer"; } -} -function warnIfSuspenseResolutionNotWrappedWithActDEV(root) { - { - if ( - root.tag !== LegacyRoot && - isConcurrentActEnvironment() && - ReactCurrentActQueue.current === null - ) { - error( - "A suspended resource finished loading inside a test, but the event " + - "was not wrapped in act(...).\n\n" + - "When testing, code that resolves suspended data should be wrapped " + - "into act(...):\n\n" + - "act(() => {\n" + - " /* finish loading suspended data */\n" + - "});\n" + - "/* assert on the output */\n\n" + - "This ensures that you're testing the behavior the user would see " + - "in the browser." + - " Learn more at https://reactjs.org/link/wrap-tests-with-act" - ); - } + var fromNode = from == null ? win : getNodeFromInstance(from); + var toNode = to == null ? win : getNodeFromInstance(to); + var leave = new SyntheticEventCtor( + leaveEventType, + eventTypePrefix + "leave", + from, + nativeEvent, + nativeEventTarget + ); + leave.target = fromNode; + leave.relatedTarget = toNode; + var enter = null; // We should only process this nativeEvent if we are processing + // the first ancestor. Next time, we will ignore the event. + + var nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget); + + if (nativeTargetInst === targetInst) { + var enterEvent = new SyntheticEventCtor( + enterEventType, + eventTypePrefix + "enter", + to, + nativeEvent, + nativeEventTarget + ); + enterEvent.target = toNode; + enterEvent.relatedTarget = fromNode; + enter = enterEvent; } + + accumulateEnterLeaveTwoPhaseListeners(dispatchQueue, leave, enter, from, to); } -function setIsRunningInsertionEffect(isRunning) { - { - isRunningInsertionEffect = isRunning; - } +var skipSelectionChangeEvent = + canUseDOM && "documentMode" in document && document.documentMode <= 11; + +function registerEvents() { + registerTwoPhaseEvent("onSelect", [ + "focusout", + "contextmenu", + "dragend", + "focusin", + "keydown", + "keyup", + "mousedown", + "mouseup", + "selectionchange" + ]); } -/* eslint-disable react-internal/prod-error-codes */ -// Used by React Refresh runtime through DevTools Global Hook. +var activeElement = null; +var activeElementInst = null; +var lastSelection = null; +var mouseDown = false; +/** + * Get an object which is a unique representation of the current selection. + * + * The return value will not be consistent across nodes or browsers, but + * two identical selections on the same node will return identical objects. + */ -var resolveFamily = null; -var failedBoundaries = null; -var setRefreshHandler = function (handler) { - { - resolveFamily = handler; +function getSelection(node) { + if ("selectionStart" in node && hasSelectionCapabilities(node)) { + return { + start: node.selectionStart, + end: node.selectionEnd + }; + } else { + var win = (node.ownerDocument && node.ownerDocument.defaultView) || window; + var selection = win.getSelection(); + return { + anchorNode: selection.anchorNode, + anchorOffset: selection.anchorOffset, + focusNode: selection.focusNode, + focusOffset: selection.focusOffset + }; } -}; -function resolveFunctionForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } +} +/** + * Get document associated with the event target. + */ - var family = resolveFamily(type); +function getEventTargetDocument(eventTarget) { + return eventTarget.window === eventTarget + ? eventTarget.document + : eventTarget.nodeType === DOCUMENT_NODE + ? eventTarget + : eventTarget.ownerDocument; +} +/** + * Poll selection to see whether it's changed. + * + * @param {object} nativeEvent + * @param {object} nativeEventTarget + * @return {?SyntheticEvent} + */ - if (family === undefined) { - return type; - } // Use the latest known implementation. +function constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) { + // Ensure we have the right element, and that the user is not dragging a + // selection (this matches native `select` event behavior). In HTML5, select + // fires only on input and textarea thus if there's no focused element we + // won't dispatch. + var doc = getEventTargetDocument(nativeEventTarget); + + if ( + mouseDown || + activeElement == null || + activeElement !== getActiveElement(doc) + ) { + return; + } // Only fire when selection has actually changed. + + var currentSelection = getSelection(activeElement); - return family.current; + if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { + lastSelection = currentSelection; + var listeners = accumulateTwoPhaseListeners(activeElementInst, "onSelect"); + + if (listeners.length > 0) { + var event = new SyntheticEvent( + "onSelect", + "select", + null, + nativeEvent, + nativeEventTarget + ); + dispatchQueue.push({ + event: event, + listeners: listeners + }); + event.target = activeElement; + } } } -function resolveClassForHotReloading(type) { - // No implementation differences. - return resolveFunctionForHotReloading(type); -} -function resolveForwardRefForHotReloading(type) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return type; - } +/** + * This plugin creates an `onSelect` event that normalizes select events + * across form elements. + * + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - contentEditable + * + * This differs from native browser implementations in the following ways: + * - Fires on contentEditable fields as well as inputs. + * - Fires for collapsed selection. + * - Fires after user input. + */ - var family = resolveFamily(type); +function extractEvents$2( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer +) { + var targetNode = targetInst ? getNodeFromInstance(targetInst) : window; - if (family === undefined) { - // Check if we're dealing with a real forwardRef. Don't want to crash early. + switch (domEventName) { + // Track the input node that has focus. + case "focusin": if ( - type !== null && - type !== undefined && - typeof type.render === "function" + isTextInputElement(targetNode) || + targetNode.contentEditable === "true" ) { - // ForwardRef is special because its resolved .type is an object, - // but it's possible that we only have its inner render function in the map. - // If that inner render function is different, we'll build a new forwardRef type. - var currentRender = resolveFunctionForHotReloading(type.render); - - if (type.render !== currentRender) { - var syntheticType = { - $$typeof: REACT_FORWARD_REF_TYPE, - render: currentRender - }; - - if (type.displayName !== undefined) { - syntheticType.displayName = type.displayName; - } - - return syntheticType; - } + activeElement = targetNode; + activeElementInst = targetInst; + lastSelection = null; } - return type; - } // Use the latest known implementation. - - return family.current; - } -} -function isCompatibleFamilyForHotReloading(fiber, element) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return false; - } + break; - var prevType = fiber.elementType; - var nextType = element.type; // If we got here, we know types aren't === equal. + case "focusout": + activeElement = null; + activeElementInst = null; + lastSelection = null; + break; + // Don't fire the event while the user is dragging. This matches the + // semantics of the native select event. - var needsCompareFamilies = false; - var $$typeofNextType = - typeof nextType === "object" && nextType !== null - ? nextType.$$typeof - : null; + case "mousedown": + mouseDown = true; + break; - switch (fiber.tag) { - case ClassComponent: { - if (typeof nextType === "function") { - needsCompareFamilies = true; - } + case "contextmenu": + case "mouseup": + case "dragend": + mouseDown = false; + constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget); + break; + // Chrome and IE fire non-standard event when selection is changed (and + // sometimes when it hasn't). IE's event fires out of order with respect + // to key and input events on deletion, so we discard it. + // + // Firefox doesn't support selectionchange, so check selection status + // after each key entry. The selection changes after keydown and before + // keyup, but we check on keydown as well in the case of holding down a + // key, when multiple keydown events are fired but only one keyup is. + // This is also our approach for IE handling, for the reason above. + case "selectionchange": + if (skipSelectionChangeEvent) { break; } - case FunctionComponent: { - if (typeof nextType === "function") { - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - // We don't know the inner type yet. - // We're going to assume that the lazy inner type is stable, - // and so it is sufficient to avoid reconciling it away. - // We're not going to unwrap or actually use the new lazy type. - needsCompareFamilies = true; - } + // falls through - break; - } + case "keydown": + case "keyup": + constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget); + } +} - case ForwardRef: { - if ($$typeofNextType === REACT_FORWARD_REF_TYPE) { - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - needsCompareFamilies = true; - } +/** + * Generate a mapping of standard vendor prefixes using the defined style property and event name. + * + * @param {string} styleProp + * @param {string} eventName + * @returns {object} + */ - break; - } +function makePrefixMap(styleProp, eventName) { + var prefixes = {}; + prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); + prefixes["Webkit" + styleProp] = "webkit" + eventName; + prefixes["Moz" + styleProp] = "moz" + eventName; + return prefixes; +} +/** + * A list of event names to a configurable list of vendor prefixes. + */ - case MemoComponent: - case SimpleMemoComponent: { - if ($$typeofNextType === REACT_MEMO_TYPE) { - // TODO: if it was but can no longer be simple, - // we shouldn't set this. - needsCompareFamilies = true; - } else if ($$typeofNextType === REACT_LAZY_TYPE) { - needsCompareFamilies = true; - } +var vendorPrefixes = { + animationend: makePrefixMap("Animation", "AnimationEnd"), + animationiteration: makePrefixMap("Animation", "AnimationIteration"), + animationstart: makePrefixMap("Animation", "AnimationStart"), + transitionend: makePrefixMap("Transition", "TransitionEnd") +}; +/** + * Event names that have already been detected and prefixed (if applicable). + */ - break; - } +var prefixedEventNames = {}; +/** + * Element to check for prefixes on. + */ - default: - return false; - } // Check if both types have a family and it's the same one. +var style = {}; +/** + * Bootstrap if a DOM exists. + */ - if (needsCompareFamilies) { - // Note: memo() and forwardRef() we'll compare outer rather than inner type. - // This means both of them need to be registered to preserve state. - // If we unwrapped and compared the inner types for wrappers instead, - // then we would risk falsely saying two separate memo(Foo) - // calls are equivalent because they wrap the same Foo function. - var prevFamily = resolveFamily(prevType); // $FlowFixMe[not-a-function] found when upgrading Flow +if (canUseDOM) { + style = document.createElement("div").style; // On some platforms, in particular some releases of Android 4.x, + // the un-prefixed "animation" and "transition" properties are defined on the + // style object but the events that fire will still be prefixed, so we need + // to check if the un-prefixed events are usable, and if not remove them from the map. - if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) { - return true; - } - } + if (!("AnimationEvent" in window)) { + delete vendorPrefixes.animationend.animation; + delete vendorPrefixes.animationiteration.animation; + delete vendorPrefixes.animationstart.animation; + } // Same as above - return false; + if (!("TransitionEvent" in window)) { + delete vendorPrefixes.transitionend.transition; } } -function markFailedErrorBoundaryForHotReloading(fiber) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; - } +/** + * Attempts to determine the correct vendor prefixed event name. + * + * @param {string} eventName + * @returns {string} + */ - if (typeof WeakSet !== "function") { - return; - } +function getVendorPrefixedEventName(eventName) { + if (prefixedEventNames[eventName]) { + return prefixedEventNames[eventName]; + } else if (!vendorPrefixes[eventName]) { + return eventName; + } - if (failedBoundaries === null) { - failedBoundaries = new WeakSet(); - } + var prefixMap = vendorPrefixes[eventName]; - failedBoundaries.add(fiber); - } -} -var scheduleRefresh = function (root, update) { - { - if (resolveFamily === null) { - // Hot reloading is disabled. - return; + for (var styleProp in prefixMap) { + if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { + return (prefixedEventNames[eventName] = prefixMap[styleProp]); } - - var staleFamilies = update.staleFamilies, - updatedFamilies = update.updatedFamilies; - flushPassiveEffects(); - flushSync$1(function () { - scheduleFibersWithFamiliesRecursively( - root.current, - updatedFamilies, - staleFamilies - ); - }); } -}; -var scheduleRoot = function (root, element) { - { - if (root.context !== emptyContextObject) { - // Super edge case: root has a legacy _renderSubtree context - // but we don't know the parentComponent so we can't pass it. - // Just ignore. We'll delete this with _renderSubtree code path later. - return; - } - flushPassiveEffects(); - flushSync$1(function () { - updateContainer(element, root, null, null); - }); - } -}; + return eventName; +} -function scheduleFibersWithFamiliesRecursively( - fiber, - updatedFamilies, - staleFamilies -) { - { - var alternate = fiber.alternate, - child = fiber.child, - sibling = fiber.sibling, - tag = fiber.tag, - type = fiber.type; - var candidateType = null; +var ANIMATION_END = getVendorPrefixedEventName("animationend"); +var ANIMATION_ITERATION = getVendorPrefixedEventName("animationiteration"); +var ANIMATION_START = getVendorPrefixedEventName("animationstart"); +var TRANSITION_END = getVendorPrefixedEventName("transitionend"); - switch (tag) { - case FunctionComponent: - case SimpleMemoComponent: - case ClassComponent: - candidateType = type; - break; +var topLevelEventsToReactNames = new Map(); // NOTE: Capitalization is important in this list! +// +// E.g. it needs "pointerDown", not "pointerdown". +// This is because we derive both React name ("onPointerDown") +// and DOM name ("pointerdown") from the same list. +// +// Exceptions that don't match this convention are listed separately. +// +// prettier-ignore - case ForwardRef: - candidateType = type.render; - break; - } +var simpleEventPluginEvents = ['abort', 'auxClick', 'cancel', 'canPlay', 'canPlayThrough', 'click', 'close', 'contextMenu', 'copy', 'cut', 'drag', 'dragEnd', 'dragEnter', 'dragExit', 'dragLeave', 'dragOver', 'dragStart', 'drop', 'durationChange', 'emptied', 'encrypted', 'ended', 'error', 'gotPointerCapture', 'input', 'invalid', 'keyDown', 'keyPress', 'keyUp', 'load', 'loadedData', 'loadedMetadata', 'loadStart', 'lostPointerCapture', 'mouseDown', 'mouseMove', 'mouseOut', 'mouseOver', 'mouseUp', 'paste', 'pause', 'play', 'playing', 'pointerCancel', 'pointerDown', 'pointerMove', 'pointerOut', 'pointerOver', 'pointerUp', 'progress', 'rateChange', 'reset', 'resize', 'seeked', 'seeking', 'stalled', 'submit', 'suspend', 'timeUpdate', 'touchCancel', 'touchEnd', 'touchStart', 'volumeChange', 'scroll', 'toggle', 'touchMove', 'waiting', 'wheel']; - if (resolveFamily === null) { - throw new Error("Expected resolveFamily to be set during hot reload."); - } +{ + // Special case: these two events don't have on* React handler + // and are only accessible via the createEventHandle API. + topLevelEventsToReactNames.set("beforeblur", null); + topLevelEventsToReactNames.set("afterblur", null); +} - var needsRender = false; - var needsRemount = false; +function registerSimpleEvent(domEventName, reactName) { + topLevelEventsToReactNames.set(domEventName, reactName); + registerTwoPhaseEvent(reactName, [domEventName]); +} - if (candidateType !== null) { - var family = resolveFamily(candidateType); +function registerSimpleEvents() { + for (var i = 0; i < simpleEventPluginEvents.length; i++) { + var eventName = simpleEventPluginEvents[i]; + var domEventName = eventName.toLowerCase(); + var capitalizedEvent = eventName[0].toUpperCase() + eventName.slice(1); + registerSimpleEvent(domEventName, "on" + capitalizedEvent); + } // Special cases where event names don't match. - if (family !== undefined) { - if (staleFamilies.has(family)) { - needsRemount = true; - } else if (updatedFamilies.has(family)) { - if (tag === ClassComponent) { - needsRemount = true; - } else { - needsRender = true; - } - } - } - } + registerSimpleEvent(ANIMATION_END, "onAnimationEnd"); + registerSimpleEvent(ANIMATION_ITERATION, "onAnimationIteration"); + registerSimpleEvent(ANIMATION_START, "onAnimationStart"); + registerSimpleEvent("dblclick", "onDoubleClick"); + registerSimpleEvent("focusin", "onFocus"); + registerSimpleEvent("focusout", "onBlur"); + registerSimpleEvent(TRANSITION_END, "onTransitionEnd"); +} - if (failedBoundaries !== null) { - if ( - failedBoundaries.has(fiber) || // $FlowFixMe[incompatible-use] found when upgrading Flow - (alternate !== null && failedBoundaries.has(alternate)) - ) { - needsRemount = true; - } - } +function extractEvents$1( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer +) { + var reactName = topLevelEventsToReactNames.get(domEventName); - if (needsRemount) { - fiber._debugNeedsRemount = true; - } + if (reactName === undefined) { + return; + } - if (needsRemount || needsRender) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + var SyntheticEventCtor = SyntheticEvent; + var reactEventType = domEventName; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + switch (domEventName) { + case "keypress": + // Firefox creates a keypress event for function keys too. This removes + // the unwanted keypress events. Enter is however both printable and + // non-printable. One would expect Tab to be as well (but it isn't). + if (getEventCharCode(nativeEvent) === 0) { + return; } - } - - if (child !== null && !needsRemount) { - scheduleFibersWithFamiliesRecursively( - child, - updatedFamilies, - staleFamilies - ); - } - - if (sibling !== null) { - scheduleFibersWithFamiliesRecursively( - sibling, - updatedFamilies, - staleFamilies - ); - } - } -} - -var findHostInstancesForRefresh = function (root, families) { - { - var hostInstances = new Set(); - var types = new Set( - families.map(function (family) { - return family.current; - }) - ); - findHostInstancesForMatchingFibersRecursively( - root.current, - types, - hostInstances - ); - return hostInstances; - } -}; -function findHostInstancesForMatchingFibersRecursively( - fiber, - types, - hostInstances -) { - { - var child = fiber.child, - sibling = fiber.sibling, - tag = fiber.tag, - type = fiber.type; - var candidateType = null; + /* falls through */ - switch (tag) { - case FunctionComponent: - case SimpleMemoComponent: - case ClassComponent: - candidateType = type; - break; + case "keydown": + case "keyup": + SyntheticEventCtor = SyntheticKeyboardEvent; + break; - case ForwardRef: - candidateType = type.render; - break; - } + case "focusin": + reactEventType = "focus"; + SyntheticEventCtor = SyntheticFocusEvent; + break; - var didMatch = false; + case "focusout": + reactEventType = "blur"; + SyntheticEventCtor = SyntheticFocusEvent; + break; - if (candidateType !== null) { - if (types.has(candidateType)) { - didMatch = true; - } - } + case "beforeblur": + case "afterblur": + SyntheticEventCtor = SyntheticFocusEvent; + break; - if (didMatch) { - // We have a match. This only drills down to the closest host components. - // There's no need to search deeper because for the purpose of giving - // visual feedback, "flashing" outermost parent rectangles is sufficient. - findHostInstancesForFiberShallowly(fiber, hostInstances); - } else { - // If there's no match, maybe there will be one further down in the child tree. - if (child !== null) { - findHostInstancesForMatchingFibersRecursively( - child, - types, - hostInstances - ); + case "click": + // Firefox creates a click event on right mouse clicks. This removes the + // unwanted click events. + if (nativeEvent.button === 2) { + return; } - } - if (sibling !== null) { - findHostInstancesForMatchingFibersRecursively( - sibling, - types, - hostInstances - ); - } - } -} + /* falls through */ -function findHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var foundHostInstances = findChildHostInstancesForFiberShallowly( - fiber, - hostInstances - ); + case "auxclick": + case "dblclick": + case "mousedown": + case "mousemove": + case "mouseup": // TODO: Disabled elements should not respond to mouse events - if (foundHostInstances) { - return; - } // If we didn't find any host children, fallback to closest host parent. + /* falls through */ - var node = fiber; + case "mouseout": + case "mouseover": + case "contextmenu": + SyntheticEventCtor = SyntheticMouseEvent; + break; - while (true) { - switch (node.tag) { - case HostSingleton: - case HostComponent: - hostInstances.add(node.stateNode); - return; + case "drag": + case "dragend": + case "dragenter": + case "dragexit": + case "dragleave": + case "dragover": + case "dragstart": + case "drop": + SyntheticEventCtor = SyntheticDragEvent; + break; - case HostPortal: - hostInstances.add(node.stateNode.containerInfo); - return; + case "touchcancel": + case "touchend": + case "touchmove": + case "touchstart": + SyntheticEventCtor = SyntheticTouchEvent; + break; - case HostRoot: - hostInstances.add(node.stateNode.containerInfo); - return; - } + case ANIMATION_END: + case ANIMATION_ITERATION: + case ANIMATION_START: + SyntheticEventCtor = SyntheticAnimationEvent; + break; - if (node.return === null) { - throw new Error("Expected to reach root first."); - } + case TRANSITION_END: + SyntheticEventCtor = SyntheticTransitionEvent; + break; - node = node.return; - } + case "scroll": + SyntheticEventCtor = SyntheticUIEvent; + break; + + case "wheel": + SyntheticEventCtor = SyntheticWheelEvent; + break; + + case "copy": + case "cut": + case "paste": + SyntheticEventCtor = SyntheticClipboardEvent; + break; + + case "gotpointercapture": + case "lostpointercapture": + case "pointercancel": + case "pointerdown": + case "pointermove": + case "pointerout": + case "pointerover": + case "pointerup": + SyntheticEventCtor = SyntheticPointerEvent; + break; } -} -function findChildHostInstancesForFiberShallowly(fiber, hostInstances) { - { - var node = fiber; - var foundHostInstances = false; + var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0; - while (true) { - if ( - node.tag === HostComponent || - node.tag === HostHoistable || - node.tag === HostSingleton - ) { - // We got a match. - foundHostInstances = true; - hostInstances.add(node.stateNode); // There may still be more, so keep searching. - } else if (node.child !== null) { - node.child.return = node; - node = node.child; - continue; - } + if (eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) { + var listeners = accumulateEventHandleNonManagedNodeListeners( + // TODO: this cast may not make sense for events like + // "focus" where React listens to e.g. "focusin". + reactEventType, + targetContainer, + inCapturePhase + ); - if (node === fiber) { - return foundHostInstances; - } + if (listeners.length > 0) { + // Intentionally create event lazily. + var event = new SyntheticEventCtor( + reactName, + reactEventType, + null, + nativeEvent, + nativeEventTarget + ); + dispatchQueue.push({ + event: event, + listeners: listeners + }); + } + } else { + // Some events don't bubble in the browser. + // In the past, React has always bubbled them, but this can be surprising. + // We're going to try aligning closer to the browser behavior by not bubbling + // them in React either. We'll start by not bubbling onScroll, and then expand. + var accumulateTargetOnly = + !inCapturePhase && // TODO: ideally, we'd eventually add all events from + // nonDelegatedEvents list in DOMPluginEventSystem. + // Then we can remove this special list. + // This is a breaking change that can wait until React 18. + domEventName === "scroll"; - while (node.sibling === null) { - if (node.return === null || node.return === fiber) { - return foundHostInstances; - } + var _listeners = accumulateSinglePhaseListeners( + targetInst, + reactName, + nativeEvent.type, + inCapturePhase, + accumulateTargetOnly, + nativeEvent + ); - node = node.return; - } + if (_listeners.length > 0) { + // Intentionally create event lazily. + var _event = new SyntheticEventCtor( + reactName, + reactEventType, + null, + nativeEvent, + nativeEventTarget + ); - node.sibling.return = node.return; - node = node.sibling; + dispatchQueue.push({ + event: _event, + listeners: _listeners + }); } } - - return false; } -var hasBadMapPolyfill; - -{ - hasBadMapPolyfill = false; +registerSimpleEvents(); +registerEvents$1(); +registerEvents$2(); +registerEvents(); +registerEvents$3(); - try { - var nonExtensibleObject = Object.preventExtensions({}); - /* eslint-disable no-new */ +function extractEvents( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer +) { + // TODO: we should remove the concept of a "SimpleEventPlugin". + // This is the basic functionality of the event system. All + // the other plugins are essentially polyfills. So the plugin + // should probably be inlined somewhere and have its logic + // be core the to event system. This would potentially allow + // us to ship builds of React without the polyfilled plugins below. + extractEvents$1( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer + ); + var shouldProcessPolyfillPlugins = + (eventSystemFlags & SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS) === 0; // We don't process these events unless we are in the + // event's native "bubble" phase, which means that we're + // not in the capture phase. That's because we emulate + // the capture phase here still. This is a trade-off, + // because in an ideal world we would not emulate and use + // the phases properly, like we do with the SimpleEvent + // plugin. However, the plugins below either expect + // emulation (EnterLeave) or use state localized to that + // plugin (BeforeInput, Change, Select). The state in + // these modules complicates things, as you'll essentially + // get the case where the capture phase event might change + // state, only for the following bubble event to come in + // later and not trigger anything as the state now + // invalidates the heuristics of the event plugin. We + // could alter all these plugins to work in such ways, but + // that might cause other unknown side-effects that we + // can't foresee right now. - new Map([[nonExtensibleObject, null]]); - new Set([nonExtensibleObject]); - /* eslint-enable no-new */ - } catch (e) { - // TODO: Consider warning about bad polyfills - hasBadMapPolyfill = true; + if (shouldProcessPolyfillPlugins) { + extractEvents$3( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget + ); + extractEvents$4( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget + ); + extractEvents$2( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget + ); + extractEvents$5( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget + ); } -} +} // List of events that need to be individually attached to media elements. -function FiberNode(tag, pendingProps, key, mode) { - // Instance - this.tag = tag; - this.key = key; - this.elementType = null; - this.type = null; - this.stateNode = null; // Fiber +var mediaEventTypes = [ + "abort", + "canplay", + "canplaythrough", + "durationchange", + "emptied", + "encrypted", + "ended", + "error", + "loadeddata", + "loadedmetadata", + "loadstart", + "pause", + "play", + "playing", + "progress", + "ratechange", + "resize", + "seeked", + "seeking", + "stalled", + "suspend", + "timeupdate", + "volumechange", + "waiting" +]; // We should not delegate these events to the container, but rather +// set them on the actual target element itself. This is primarily +// because these events do not consistently bubble in the DOM. - this.return = null; - this.child = null; - this.sibling = null; - this.index = 0; - this.ref = null; - this.refCleanup = null; - this.pendingProps = pendingProps; - this.memoizedProps = null; - this.updateQueue = null; - this.memoizedState = null; - this.dependencies = null; - this.mode = mode; // Effects +var nonDelegatedEvents = new Set( + ["cancel", "close", "invalid", "load", "scroll", "toggle"].concat( + mediaEventTypes + ) +); - this.flags = NoFlags$1; - this.subtreeFlags = NoFlags$1; - this.deletions = null; - this.lanes = NoLanes; - this.childLanes = NoLanes; - this.alternate = null; +function executeDispatch(event, listener, currentTarget) { + var type = event.type || "unknown-event"; + event.currentTarget = currentTarget; + invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); + event.currentTarget = null; +} - { - // 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). +function processDispatchQueueItemsInOrder( + event, + dispatchListeners, + inCapturePhase +) { + var previousInstance; - this.actualDuration = 0; - this.actualStartTime = -1; - this.selfBaseDuration = 0; - this.treeBaseDuration = 0; - } + if (inCapturePhase) { + for (var i = dispatchListeners.length - 1; i >= 0; i--) { + var _dispatchListeners$i = dispatchListeners[i], + instance = _dispatchListeners$i.instance, + currentTarget = _dispatchListeners$i.currentTarget, + listener = _dispatchListeners$i.listener; - { - // This isn't directly used but is handy for debugging internals: - this._debugSource = null; - this._debugOwner = null; - this._debugNeedsRemount = false; - this._debugHookTypes = null; + if (instance !== previousInstance && event.isPropagationStopped()) { + return; + } - if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { - Object.preventExtensions(this); + executeDispatch(event, listener, currentTarget); + previousInstance = instance; } - } -} // 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. + } else { + for (var _i = 0; _i < dispatchListeners.length; _i++) { + var _dispatchListeners$_i = dispatchListeners[_i], + _instance = _dispatchListeners$_i.instance, + _currentTarget = _dispatchListeners$_i.currentTarget, + _listener = _dispatchListeners$_i.listener; -function createFiber(tag, pendingProps, key, mode) { - // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, pendingProps, key, mode); + if (_instance !== previousInstance && event.isPropagationStopped()) { + return; + } + + executeDispatch(event, _listener, _currentTarget); + previousInstance = _instance; + } + } } -function shouldConstruct(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); +function processDispatchQueue(dispatchQueue, eventSystemFlags) { + var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0; + + for (var i = 0; i < dispatchQueue.length; i++) { + var _dispatchQueue$i = dispatchQueue[i], + event = _dispatchQueue$i.event, + listeners = _dispatchQueue$i.listeners; + processDispatchQueueItemsInOrder(event, listeners, inCapturePhase); // event system doesn't use pooling. + } // This would be a good time to rethrow if any of the event handlers threw. + + rethrowCaughtError(); } -function isSimpleFunctionComponent(type) { - return ( - typeof type === "function" && - !shouldConstruct(type) && - type.defaultProps === undefined +function dispatchEventsForPlugins( + domEventName, + eventSystemFlags, + nativeEvent, + targetInst, + targetContainer +) { + var nativeEventTarget = getEventTarget(nativeEvent); + var dispatchQueue = []; + extractEvents( + dispatchQueue, + domEventName, + targetInst, + nativeEvent, + nativeEventTarget, + eventSystemFlags, + targetContainer ); + processDispatchQueue(dispatchQueue, eventSystemFlags); } -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; +function listenToNonDelegatedEvent(domEventName, targetElement) { + { + if (!nonDelegatedEvents.has(domEventName)) { + error( + 'Did not expect a listenToNonDelegatedEvent() call for "%s". ' + + "This is a bug in React. Please file an issue.", + domEventName + ); } } - return IndeterminateComponent; -} // This is used to create an alternate fiber to do work on. - -function createWorkInProgress(current, pendingProps) { - 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; + var isCapturePhaseListener = false; + var listenerSet = getEventListenerSet(targetElement); + var listenerSetKey = getListenerSetKey(domEventName, isCapturePhaseListener); - { - // DEV-only fields - workInProgress._debugSource = current._debugSource; - workInProgress._debugOwner = current._debugOwner; - workInProgress._debugHookTypes = current._debugHookTypes; + if (!listenerSet.has(listenerSetKey)) { + addTrappedEventListener( + targetElement, + domEventName, + IS_NON_DELEGATED, + isCapturePhaseListener + ); + listenerSet.add(listenerSetKey); + } +} +function listenToNativeEvent(domEventName, isCapturePhaseListener, target) { + { + if (nonDelegatedEvents.has(domEventName) && !isCapturePhaseListener) { + error( + 'Did not expect a listenToNativeEvent() call for "%s" in the bubble phase. ' + + "This is a bug in React. Please file an issue.", + domEventName + ); } + } - workInProgress.alternate = current; - current.alternate = workInProgress; - } else { - workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type. + var eventSystemFlags = 0; - workInProgress.type = current.type; // We already have an alternate. - // Reset the effect tag. + if (isCapturePhaseListener) { + eventSystemFlags |= IS_CAPTURE_PHASE; + } - workInProgress.flags = NoFlags$1; // The effects are no longer valid. + addTrappedEventListener( + target, + domEventName, + eventSystemFlags, + isCapturePhaseListener + ); +} // This is only used by createEventHandle when the +// target is not a DOM element. E.g. window. - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.deletions = null; +function listenToNativeEventForNonManagedEventTarget( + domEventName, + isCapturePhaseListener, + target +) { + var eventSystemFlags = IS_EVENT_HANDLE_NON_MANAGED_NODE; + var listenerSet = getEventListenerSet(target); + var listenerSetKey = getListenerSetKey(domEventName, isCapturePhaseListener); - { - // 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; + if (!listenerSet.has(listenerSetKey)) { + if (isCapturePhaseListener) { + eventSystemFlags |= IS_CAPTURE_PHASE; } - } // Reset all effects except static ones. - // Static effects are not specific to a render. - - workInProgress.flags = current.flags & StaticMask; - workInProgress.childLanes = current.childLanes; - workInProgress.lanes = current.lanes; - workInProgress.child = current.child; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated during the render phase, so - // it cannot be shared with the current fiber. - var currentDependencies = current.dependencies; - workInProgress.dependencies = - currentDependencies === null - ? null - : { - lanes: currentDependencies.lanes, - firstContext: currentDependencies.firstContext - }; // These will be overridden during the parent's reconciliation + addTrappedEventListener( + target, + domEventName, + eventSystemFlags, + isCapturePhaseListener + ); + listenerSet.add(listenerSetKey); + } +} +var listeningMarker = "_reactListening" + Math.random().toString(36).slice(2); +function listenToAllSupportedEvents(rootContainerElement) { + if (!rootContainerElement[listeningMarker]) { + rootContainerElement[listeningMarker] = true; + allNativeEvents.forEach(function (domEventName) { + // We handle selectionchange separately because it + // doesn't bubble and needs to be on the document. + if (domEventName !== "selectionchange") { + if (!nonDelegatedEvents.has(domEventName)) { + listenToNativeEvent(domEventName, false, rootContainerElement); + } - workInProgress.sibling = current.sibling; - workInProgress.index = current.index; - workInProgress.ref = current.ref; - workInProgress.refCleanup = current.refCleanup; + listenToNativeEvent(domEventName, true, rootContainerElement); + } + }); + var ownerDocument = + rootContainerElement.nodeType === DOCUMENT_NODE + ? rootContainerElement + : rootContainerElement.ownerDocument; - { - workInProgress.selfBaseDuration = current.selfBaseDuration; - workInProgress.treeBaseDuration = current.treeBaseDuration; + if (ownerDocument !== null) { + // The selectionchange event also needs deduplication + // but it is attached to the document. + if (!ownerDocument[listeningMarker]) { + ownerDocument[listeningMarker] = true; + listenToNativeEvent("selectionchange", false, ownerDocument); + } + } } +} - { - workInProgress._debugNeedsRemount = current._debugNeedsRemount; - - switch (workInProgress.tag) { - case IndeterminateComponent: - case FunctionComponent: - case SimpleMemoComponent: - workInProgress.type = resolveFunctionForHotReloading(current.type); - break; +function addTrappedEventListener( + targetContainer, + domEventName, + eventSystemFlags, + isCapturePhaseListener, + isDeferredListenerForLegacyFBSupport +) { + var listener = createEventListenerWrapperWithPriority( + targetContainer, + domEventName, + eventSystemFlags + ); // If passive option is not supported, then the event will be + // active and not passive. - case ClassComponent: - workInProgress.type = resolveClassForHotReloading(current.type); - break; + var isPassiveListener = undefined; - case ForwardRef: - workInProgress.type = resolveForwardRefForHotReloading(current.type); - break; + if (passiveBrowserEventsSupported) { + // Browsers introduced an intervention, making these events + // passive by default on document. React doesn't bind them + // to document anymore, but changing this now would undo + // the performance wins from the change. So we emulate + // the existing behavior manually on the roots now. + // https://github.com/facebook/react/issues/19651 + if ( + domEventName === "touchstart" || + domEventName === "touchmove" || + domEventName === "wheel" + ) { + isPassiveListener = true; } } - return workInProgress; -} // Used to reuse a Fiber for a second pass. + targetContainer = + enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport + ? targetContainer.ownerDocument + : targetContainer; + var unsubscribeListener; // When legacyFBSupport is enabled, it's for when we + // want to add a one time event listener to a container. + // This should only be used with enableLegacyFBSupport + // due to requirement to provide compatibility with + // internal FB www event tooling. This works by removing + // the event listener as soon as it is invoked. We could + // also attempt to use the {once: true} param on + // addEventListener, but that requires support and some + // browsers do not support this today, and given this is + // to support legacy code patterns, it's likely they'll + // need support for such browsers. -function resetWorkInProgress(workInProgress, renderLanes) { - // This resets the Fiber to what createFiber or createWorkInProgress would - // have set the values to before during the first pass. Ideally this wouldn't - // be necessary but unfortunately many code paths reads from the workInProgress - // when they should be reading from current and writing to workInProgress. - // We assume pendingProps, index, key, ref, return are still untouched to - // avoid doing another reconciliation. - // Reset the effect flags but keep any Placement tags, since that's something - // that child fiber is setting, not the reconciliation. - workInProgress.flags &= StaticMask | Placement; // The effects are no longer valid. + if (enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport) { + var originalListener = listener; // $FlowFixMe[missing-this-annot] + // $FlowFixMe[definition-cycle] - var current = workInProgress.alternate; + listener = function () { + removeEventListener(targetContainer, domEventName, unsubscribeListener); - if (current === null) { - // Reset to createFiber's initial values. - workInProgress.childLanes = NoLanes; - workInProgress.lanes = renderLanes; - workInProgress.child = null; - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.memoizedProps = null; - workInProgress.memoizedState = null; - workInProgress.updateQueue = null; - workInProgress.dependencies = null; - workInProgress.stateNode = null; + for ( + var _len = arguments.length, p = new Array(_len), _key = 0; + _key < _len; + _key++ + ) { + p[_key] = arguments[_key]; + } - { - // Note: We don't reset the actualTime counts. It's useful to accumulate - // actual time across multiple render passes. - workInProgress.selfBaseDuration = 0; - workInProgress.treeBaseDuration = 0; + return originalListener.apply(this, p); + }; + } // TODO: There are too many combinations here. Consolidate them. + + if (isCapturePhaseListener) { + if (isPassiveListener !== undefined) { + unsubscribeListener = addEventCaptureListenerWithPassiveFlag( + targetContainer, + domEventName, + listener, + isPassiveListener + ); + } else { + unsubscribeListener = addEventCaptureListener( + targetContainer, + domEventName, + listener + ); } } else { - // Reset to the cloned values that createWorkInProgress would've. - workInProgress.childLanes = current.childLanes; - workInProgress.lanes = current.lanes; - workInProgress.child = current.child; - workInProgress.subtreeFlags = NoFlags$1; - workInProgress.deletions = null; - workInProgress.memoizedProps = current.memoizedProps; - workInProgress.memoizedState = current.memoizedState; - workInProgress.updateQueue = current.updateQueue; // Needed because Blocks store data on type. - - workInProgress.type = current.type; // Clone the dependencies object. This is mutated during the render phase, so - // it cannot be shared with the current fiber. - - var currentDependencies = current.dependencies; - workInProgress.dependencies = - currentDependencies === null - ? null - : { - lanes: currentDependencies.lanes, - firstContext: currentDependencies.firstContext - }; - - { - // Note: We don't reset the actualTime counts. It's useful to accumulate - // actual time across multiple render passes. - workInProgress.selfBaseDuration = current.selfBaseDuration; - workInProgress.treeBaseDuration = current.treeBaseDuration; + if (isPassiveListener !== undefined) { + unsubscribeListener = addEventBubbleListenerWithPassiveFlag( + targetContainer, + domEventName, + listener, + isPassiveListener + ); + } else { + unsubscribeListener = addEventBubbleListener( + targetContainer, + domEventName, + listener + ); } } +} - return workInProgress; +function deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer) { + // We defer all click events with legacy FB support mode on. + // This means we add a one time event listener to trigger + // after the FB delegated listeners fire. + var isDeferredListenerForLegacyFBSupport = true; + addTrappedEventListener( + targetContainer, + domEventName, + IS_LEGACY_FB_SUPPORT_MODE, + false, + isDeferredListenerForLegacyFBSupport + ); } -function createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride -) { - var mode; - if (tag === ConcurrentRoot) { - mode = ConcurrentMode; +function isMatchingRootContainer(grandContainer, targetContainer) { + return ( + grandContainer === targetContainer || + (grandContainer.nodeType === COMMENT_NODE && + grandContainer.parentNode === targetContainer) + ); +} - if (isStrictMode === true || createRootStrictEffectsByDefault) { - mode |= StrictLegacyMode | StrictEffectsMode; - } +function dispatchEventForPluginEventSystem( + domEventName, + eventSystemFlags, + nativeEvent, + targetInst, + targetContainer +) { + var ancestorInst = targetInst; + + if ( + (eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) === 0 && + (eventSystemFlags & IS_NON_DELEGATED) === 0 + ) { + var targetContainerNode = targetContainer; // If we are using the legacy FB support flag, we + // defer the event to the null with a one + // time event listener so we can defer the event. if ( - // Only for internal experiments. - concurrentUpdatesByDefaultOverride + enableLegacyFBSupport && // If our event flags match the required flags for entering + // FB legacy mode and we are processing the "click" event, + // then we can defer the event to the "document", to allow + // for legacy FB support, where the expected behavior was to + // match React < 16 behavior of delegated clicks to the doc. + domEventName === "click" && + (eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0 && + !isReplayingEvent(nativeEvent) ) { - mode |= ConcurrentUpdatesByDefaultMode; + deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer); + return; } - } else { - mode = NoMode; - } - if (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; - } + if (targetInst !== null) { + // The below logic attempts to work out if we need to change + // the target fiber to a different ancestor. We had similar logic + // in the legacy event system, except the big difference between + // systems is that the modern event system now has an event listener + // attached to each React Root and React Portal Root. Together, + // the DOM nodes representing these roots are the "rootContainer". + // To figure out which ancestor instance we should use, we traverse + // up the fiber tree from the target instance and attempt to find + // root boundaries that match that of our current "rootContainer". + // If we find that "rootContainer", we find the parent fiber + // sub-tree for that root and make that our ancestor instance. + var node = targetInst; - return createFiber(HostRoot, null, null, mode); -} -function createFiberFromTypeAndProps( - type, // React$ElementType - key, - pendingProps, - owner, - mode, - lanes -) { - var fiberTag = IndeterminateComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy. + mainLoop: while (true) { + if (node === null) { + return; + } - var resolvedType = type; + var nodeTag = node.tag; - if (typeof type === "function") { - if (shouldConstruct(type)) { - fiberTag = ClassComponent; + if (nodeTag === HostRoot || nodeTag === HostPortal) { + var container = node.stateNode.containerInfo; - { - resolvedType = resolveClassForHotReloading(resolvedType); - } - } else { - { - resolvedType = resolveFunctionForHotReloading(resolvedType); - } - } - } else if (typeof type === "string") { - { - var hostContext = getHostContext(); - fiberTag = isHostHoistableType(type, pendingProps, hostContext) - ? HostHoistable - : isHostSingletonType(type) - ? HostSingleton - : HostComponent; - } - } else { - getTag: switch (type) { - case REACT_FRAGMENT_TYPE: - return createFiberFromFragment(pendingProps.children, mode, lanes, key); + if (isMatchingRootContainer(container, targetContainerNode)) { + break; + } - case REACT_STRICT_MODE_TYPE: - fiberTag = Mode; - mode |= StrictLegacyMode; + if (nodeTag === HostPortal) { + // The target is a portal, but it's not the rootContainer we're looking for. + // Normally portals handle their own events all the way down to the root. + // So we should be able to stop now. However, we don't know if this portal + // was part of *our* root. + var grandNode = node.return; - if ((mode & ConcurrentMode) !== NoMode) { - // Strict effects should never run on legacy roots - mode |= StrictEffectsMode; - } + while (grandNode !== null) { + var grandTag = grandNode.tag; - break; + if (grandTag === HostRoot || grandTag === HostPortal) { + var grandContainer = grandNode.stateNode.containerInfo; - case REACT_PROFILER_TYPE: - return createFiberFromProfiler(pendingProps, mode, lanes, key); + if ( + isMatchingRootContainer(grandContainer, targetContainerNode) + ) { + // This is the rootContainer we're looking for and we found it as + // a parent of the Portal. That means we can ignore it because the + // Portal will bubble through to us. + return; + } + } - case REACT_SUSPENSE_TYPE: - return createFiberFromSuspense(pendingProps, mode, lanes, key); + grandNode = grandNode.return; + } + } // Now we need to find it's corresponding host fiber in the other + // tree. To do this we can use getClosestInstanceFromNode, but we + // need to validate that the fiber is a host instance, otherwise + // we need to traverse up through the DOM till we find the correct + // node that is from the other tree. - case REACT_SUSPENSE_LIST_TYPE: - return createFiberFromSuspenseList(pendingProps, mode, lanes, key); + while (container !== null) { + var parentNode = getClosestInstanceFromNode(container); - case REACT_OFFSCREEN_TYPE: - return createFiberFromOffscreen(pendingProps, mode, lanes, key); + if (parentNode === null) { + return; + } - case REACT_LEGACY_HIDDEN_TYPE: { - return createFiberFromLegacyHidden(pendingProps, mode, lanes, key); - } + var parentTag = parentNode.tag; - // eslint-disable-next-line no-fallthrough + if ( + parentTag === HostComponent || + parentTag === HostText || + parentTag === HostHoistable || + parentTag === HostSingleton + ) { + node = ancestorInst = parentNode; + continue mainLoop; + } - case REACT_SCOPE_TYPE: { - return createFiberFromScope(type, pendingProps, mode, lanes, key); + container = container.parentNode; + } + } + + node = node.return; } + } + } - // eslint-disable-next-line no-fallthrough + batchedUpdates(function () { + return dispatchEventsForPlugins( + domEventName, + eventSystemFlags, + nativeEvent, + ancestorInst, + targetContainer + ); + }); +} - case REACT_CACHE_TYPE: { - return createFiberFromCache(pendingProps, mode, lanes, key); - } +function createDispatchListener(instance, listener, currentTarget) { + return { + instance: instance, + listener: listener, + currentTarget: currentTarget + }; +} + +function accumulateSinglePhaseListeners( + targetFiber, + reactName, + nativeEventType, + inCapturePhase, + accumulateTargetOnly, + nativeEvent +) { + var captureName = reactName !== null ? reactName + "Capture" : null; + var reactEventName = inCapturePhase ? captureName : reactName; + var listeners = []; + var instance = targetFiber; + var lastHostComponent = null; // Accumulate all instances and listeners via the target -> root path. + + while (instance !== null) { + var _instance2 = instance, + stateNode = _instance2.stateNode, + tag = _instance2.tag; // Handle listeners that are on HostComponents (i.e.
) + + if ( + (tag === HostComponent || + tag === HostHoistable || + tag === HostSingleton) && + stateNode !== null + ) { + lastHostComponent = stateNode; // createEventHandle listeners - // eslint-disable-next-line no-fallthrough + { + var eventHandlerListeners = getEventHandlerListeners(lastHostComponent); - case REACT_TRACING_MARKER_TYPE: - if (enableTransitionTracing) { - return createFiberFromTracingMarker(pendingProps, mode, lanes, key); + if (eventHandlerListeners !== null) { + eventHandlerListeners.forEach(function (entry) { + if ( + entry.type === nativeEventType && + entry.capture === inCapturePhase + ) { + listeners.push( + createDispatchListener( + instance, + entry.callback, + lastHostComponent + ) + ); + } + }); } + } // Standard React on* listeners, i.e. onClick or onClickCapture - // eslint-disable-next-line no-fallthrough + if (reactEventName !== null) { + var listener = getListener(instance, reactEventName); - case REACT_DEBUG_TRACING_MODE_TYPE: - if (enableDebugTracing) { - fiberTag = Mode; - mode |= DebugTracingMode; - break; + if (listener != null) { + listeners.push( + createDispatchListener(instance, listener, lastHostComponent) + ); } + } + } else if ( + tag === ScopeComponent && + lastHostComponent !== null && + stateNode !== null + ) { + // Scopes + var reactScopeInstance = stateNode; - // eslint-disable-next-line no-fallthrough + var _eventHandlerListeners = getEventHandlerListeners(reactScopeInstance); - default: { - if (typeof type === "object" && type !== null) { - switch (type.$$typeof) { - case REACT_PROVIDER_TYPE: - fiberTag = ContextProvider; - break getTag; + if (_eventHandlerListeners !== null) { + _eventHandlerListeners.forEach(function (entry) { + if ( + entry.type === nativeEventType && + entry.capture === inCapturePhase + ) { + listeners.push( + createDispatchListener( + instance, + entry.callback, + lastHostComponent + ) + ); + } + }); + } + } // If we are only accumulating events for the target, then we don't + // continue to propagate through the React fiber tree to find other + // listeners. - case REACT_CONTEXT_TYPE: - // This is a consumer - fiberTag = ContextConsumer; - break getTag; + if (accumulateTargetOnly) { + break; + } // If we are processing the onBeforeBlur event, then we need to take + // into consideration that part of the React tree might have been hidden + // or deleted (as we're invoking this event during commit). We can find + // this out by checking if intercept fiber set on the event matches the + // current instance fiber. In which case, we should clear all existing + // listeners. - case REACT_FORWARD_REF_TYPE: - fiberTag = ForwardRef; + if (nativeEvent.type === "beforeblur") { + // $FlowFixMe[prop-missing] internal field + var detachedInterceptFiber = nativeEvent._detachedInterceptFiber; - { - resolvedType = resolveForwardRefForHotReloading(resolvedType); - } + if ( + detachedInterceptFiber !== null && + (detachedInterceptFiber === instance || + detachedInterceptFiber === instance.alternate) + ) { + listeners = []; + } + } - break getTag; + instance = instance.return; + } - case REACT_MEMO_TYPE: - fiberTag = MemoComponent; - break getTag; + return listeners; +} // We should only use this function for: +// - BeforeInputEventPlugin +// - ChangeEventPlugin +// - SelectEventPlugin +// This is because we only process these plugins +// in the bubble phase, so we need to accumulate two +// phase event listeners (via emulation). - case REACT_LAZY_TYPE: - fiberTag = LazyComponent; - resolvedType = null; - break getTag; - } - } +function accumulateTwoPhaseListeners(targetFiber, reactName) { + var captureName = reactName + "Capture"; + var listeners = []; + var instance = targetFiber; // Accumulate all instances and listeners via the target -> root path. - var info = ""; + while (instance !== null) { + var _instance3 = instance, + stateNode = _instance3.stateNode, + tag = _instance3.tag; // Handle listeners that are on HostComponents (i.e.
) - { - if ( - type === undefined || - (typeof type === "object" && - type !== null && - Object.keys(type).length === 0) - ) { - info += - " You likely forgot to export your component from the file " + - "it's defined in, or you might have mixed up default and " + - "named imports."; - } + if ( + (tag === HostComponent || + tag === HostHoistable || + tag === HostSingleton) && + stateNode !== null + ) { + var currentTarget = stateNode; + var captureListener = getListener(instance, captureName); - var ownerName = owner ? getComponentNameFromFiber(owner) : null; + if (captureListener != null) { + listeners.unshift( + createDispatchListener(instance, captureListener, currentTarget) + ); + } - if (ownerName) { - info += "\n\nCheck the render method of `" + ownerName + "`."; - } - } + var bubbleListener = getListener(instance, reactName); - throw new Error( - "Element type is invalid: expected a string (for built-in " + - "components) or a class/function (for composite components) " + - ("but got: " + (type == null ? type : typeof type) + "." + info) + if (bubbleListener != null) { + listeners.push( + createDispatchListener(instance, bubbleListener, currentTarget) ); } } - } - - var fiber = createFiber(fiberTag, pendingProps, key, mode); - fiber.elementType = type; - fiber.type = resolvedType; - fiber.lanes = lanes; - { - fiber._debugOwner = owner; + instance = instance.return; } - return fiber; + return listeners; } -function createFiberFromElement(element, mode, lanes) { - var owner = null; - { - owner = element._owner; +function getParent(inst) { + if (inst === null) { + return null; } - var type = element.type; - var key = element.key; - var pendingProps = element.props; - var fiber = createFiberFromTypeAndProps( - type, - key, - pendingProps, - owner, - mode, - lanes - ); + do { + // $FlowFixMe[incompatible-use] found when upgrading Flow + inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. + // That is depending on if we want nested subtrees (layers) to bubble + // events to their parent. We could also go through parentNode on the + // host node but that wouldn't work for React Native and doesn't let us + // do the portal feature. + } while (inst && inst.tag !== HostComponent && inst.tag !== HostSingleton); - { - fiber._debugSource = element._source; - fiber._debugOwner = element._owner; + if (inst) { + return inst; } - return fiber; -} -function createFiberFromFragment(elements, mode, lanes, key) { - var fiber = createFiber(Fragment, elements, key, mode); - fiber.lanes = lanes; - return fiber; + return null; } +/** + * Return the lowest common ancestor of A and B, or null if they are in + * different trees. + */ -function createFiberFromScope(scope, pendingProps, mode, lanes, key) { - var fiber = createFiber(ScopeComponent, pendingProps, key, mode); - fiber.type = scope; - fiber.elementType = scope; - fiber.lanes = lanes; - return fiber; -} +function getLowestCommonAncestor(instA, instB) { + var nodeA = instA; + var nodeB = instB; + var depthA = 0; -function createFiberFromProfiler(pendingProps, mode, lanes, key) { - { - if (typeof pendingProps.id !== "string") { - error( - 'Profiler must specify an "id" of type `string` as a prop. Received the type `%s` instead.', - typeof pendingProps.id - ); - } + for (var tempA = nodeA; tempA; tempA = getParent(tempA)) { + depthA++; } - var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); - fiber.elementType = REACT_PROFILER_TYPE; - fiber.lanes = lanes; - - { - fiber.stateNode = { - effectDuration: 0, - passiveEffectDuration: 0 - }; - } + var depthB = 0; - return fiber; -} + for (var tempB = nodeB; tempB; tempB = getParent(tempB)) { + depthB++; + } // If A is deeper, crawl up. -function createFiberFromSuspense(pendingProps, mode, lanes, key) { - var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); - fiber.elementType = REACT_SUSPENSE_TYPE; - fiber.lanes = lanes; - return fiber; -} -function createFiberFromSuspenseList(pendingProps, mode, lanes, key) { - var fiber = createFiber(SuspenseListComponent, pendingProps, key, mode); - fiber.elementType = REACT_SUSPENSE_LIST_TYPE; - fiber.lanes = lanes; - return fiber; -} -function createFiberFromOffscreen(pendingProps, mode, lanes, key) { - var fiber = createFiber(OffscreenComponent, pendingProps, key, mode); - fiber.elementType = REACT_OFFSCREEN_TYPE; - fiber.lanes = lanes; - var primaryChildInstance = { - _visibility: OffscreenVisible, - _pendingVisibility: OffscreenVisible, - _pendingMarkers: null, - _retryCache: null, - _transitions: null, - _current: null, - detach: function () { - return detachOffscreenInstance(primaryChildInstance); - }, - attach: function () { - return attachOffscreenInstance(primaryChildInstance); - } - }; - fiber.stateNode = primaryChildInstance; - return fiber; -} -function createFiberFromLegacyHidden(pendingProps, mode, lanes, key) { - var fiber = createFiber(LegacyHiddenComponent, pendingProps, key, mode); - fiber.elementType = REACT_LEGACY_HIDDEN_TYPE; - fiber.lanes = lanes; // Adding a stateNode for legacy hidden because it's currently using - // the offscreen implementation, which depends on a state node + while (depthA - depthB > 0) { + nodeA = getParent(nodeA); + depthA--; + } // If B is deeper, crawl up. - var instance = { - _visibility: OffscreenVisible, - _pendingVisibility: OffscreenVisible, - _pendingMarkers: null, - _transitions: null, - _retryCache: null, - _current: null, - detach: function () { - return detachOffscreenInstance(instance); - }, - attach: function () { - return attachOffscreenInstance(instance); - } - }; - fiber.stateNode = instance; - return fiber; -} -function createFiberFromCache(pendingProps, mode, lanes, key) { - var fiber = createFiber(CacheComponent, pendingProps, key, mode); - fiber.elementType = REACT_CACHE_TYPE; - fiber.lanes = lanes; - return fiber; -} -function createFiberFromTracingMarker(pendingProps, mode, lanes, key) { - var fiber = createFiber(TracingMarkerComponent, pendingProps, key, mode); - fiber.elementType = REACT_TRACING_MARKER_TYPE; - fiber.lanes = lanes; - var tracingMarkerInstance = { - tag: TransitionTracingMarker, - transitions: null, - pendingBoundaries: null, - aborts: null, - name: pendingProps.name - }; - fiber.stateNode = tracingMarkerInstance; - return fiber; -} -function createFiberFromText(content, mode, lanes) { - var fiber = createFiber(HostText, content, null, mode); - fiber.lanes = lanes; - return fiber; -} -function createFiberFromHostInstanceForDeletion() { - var fiber = createFiber(HostComponent, null, null, NoMode); - fiber.elementType = "DELETED"; - return fiber; -} -function createFiberFromDehydratedFragment(dehydratedNode) { - var fiber = createFiber(DehydratedFragment, null, null, NoMode); - fiber.stateNode = dehydratedNode; - return fiber; -} -function createFiberFromPortal(portal, mode, lanes) { - var pendingProps = portal.children !== null ? portal.children : []; - var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); - fiber.lanes = lanes; - 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. + while (depthB - depthA > 0) { + nodeB = getParent(nodeB); + depthB--; + } // Walk in lockstep until we find a match. -function assignFiberPropertiesInDEV(target, source) { - if (target === null) { - // This Fiber's initial properties will always be overwritten. - // We only use a Fiber to ensure the same hidden class so DEV isn't slow. - target = createFiber(IndeterminateComponent, null, null, NoMode); - } // This is intentionally written as a list of all properties. - // We tried to use Object.assign() instead but this is called in - // the hottest path, and Object.assign() was too slow: - // https://github.com/facebook/react/issues/12502 - // This code is DEV-only so size is not a concern. + var depth = depthA; - target.tag = source.tag; - target.key = source.key; - target.elementType = source.elementType; - target.type = source.type; - target.stateNode = source.stateNode; - target.return = source.return; - target.child = source.child; - target.sibling = source.sibling; - target.index = source.index; - target.ref = source.ref; - target.refCleanup = source.refCleanup; - target.pendingProps = source.pendingProps; - target.memoizedProps = source.memoizedProps; - target.updateQueue = source.updateQueue; - target.memoizedState = source.memoizedState; - target.dependencies = source.dependencies; - target.mode = source.mode; - target.flags = source.flags; - target.subtreeFlags = source.subtreeFlags; - target.deletions = source.deletions; - target.lanes = source.lanes; - target.childLanes = source.childLanes; - target.alternate = source.alternate; + while (depth--) { + if (nodeA === nodeB || (nodeB !== null && nodeA === nodeB.alternate)) { + return nodeA; + } - { - target.actualDuration = source.actualDuration; - target.actualStartTime = source.actualStartTime; - target.selfBaseDuration = source.selfBaseDuration; - target.treeBaseDuration = source.treeBaseDuration; + nodeA = getParent(nodeA); + nodeB = getParent(nodeB); } - target._debugSource = source._debugSource; - target._debugOwner = source._debugOwner; - target._debugNeedsRemount = source._debugNeedsRemount; - target._debugHookTypes = source._debugHookTypes; - return target; + return null; } -function FiberRootNode( - containerInfo, // $FlowFixMe[missing-local-annot] - tag, - hydrate, - identifierPrefix, - onRecoverableError +function accumulateEnterLeaveListenersForEvent( + dispatchQueue, + event, + target, + common, + inCapturePhase ) { - this.tag = tag; - this.containerInfo = containerInfo; - this.pendingChildren = null; - this.current = null; - this.pingCache = null; - this.finishedWork = null; - this.timeoutHandle = noTimeout; - this.context = null; - this.pendingContext = null; - this.callbackNode = null; - this.callbackPriority = NoLane; - this.eventTimes = createLaneMap(NoLanes); - this.expirationTimes = createLaneMap(NoTimestamp); - this.pendingLanes = NoLanes; - this.suspendedLanes = NoLanes; - this.pingedLanes = NoLanes; - this.expiredLanes = NoLanes; - this.mutableReadLanes = NoLanes; - this.finishedLanes = NoLanes; - this.errorRecoveryDisabledLanes = NoLanes; - this.entangledLanes = NoLanes; - this.entanglements = createLaneMap(NoLanes); - this.hiddenUpdates = createLaneMap(null); - this.identifierPrefix = identifierPrefix; - this.onRecoverableError = onRecoverableError; + var registrationName = event._reactName; + var listeners = []; + var instance = target; - { - this.pooledCache = null; - this.pooledCacheLanes = NoLanes; - } + while (instance !== null) { + if (instance === common) { + break; + } - { - this.mutableSourceEagerHydrationData = null; - } + var _instance4 = instance, + alternate = _instance4.alternate, + stateNode = _instance4.stateNode, + tag = _instance4.tag; - { - this.hydrationCallbacks = null; - } + if (alternate !== null && alternate === common) { + break; + } - this.incompleteTransitions = new Map(); + if ( + (tag === HostComponent || + tag === HostHoistable || + tag === HostSingleton) && + stateNode !== null + ) { + var currentTarget = stateNode; - if (enableTransitionTracing) { - this.transitionCallbacks = null; - var transitionLanesMap = (this.transitionLanes = []); + if (inCapturePhase) { + var captureListener = getListener(instance, registrationName); - for (var i = 0; i < TotalLanes; i++) { - transitionLanesMap.push(null); + if (captureListener != null) { + listeners.unshift( + createDispatchListener(instance, captureListener, currentTarget) + ); + } + } else if (!inCapturePhase) { + var bubbleListener = getListener(instance, registrationName); + + if (bubbleListener != null) { + listeners.push( + createDispatchListener(instance, bubbleListener, currentTarget) + ); + } + } } + + instance = instance.return; } - { - this.effectDuration = 0; - this.passiveEffectDuration = 0; + if (listeners.length !== 0) { + dispatchQueue.push({ + event: event, + listeners: listeners + }); } +} // We should only use this function for: +// - EnterLeaveEventPlugin +// This is because we only process this plugin +// in the bubble phase, so we need to accumulate two +// phase event listeners. - { - this.memoizedUpdaters = new Set(); - var pendingUpdatersLaneMap = (this.pendingUpdatersLaneMap = []); +function accumulateEnterLeaveTwoPhaseListeners( + dispatchQueue, + leaveEvent, + enterEvent, + from, + to +) { + var common = from && to ? getLowestCommonAncestor(from, to) : null; - for (var _i = 0; _i < TotalLanes; _i++) { - pendingUpdatersLaneMap.push(new Set()); - } + if (from !== null) { + accumulateEnterLeaveListenersForEvent( + dispatchQueue, + leaveEvent, + from, + common, + false + ); } - { - switch (tag) { - case ConcurrentRoot: - this._debugRootType = hydrate ? "hydrateRoot()" : "createRoot()"; - break; - - case LegacyRoot: - this._debugRootType = hydrate ? "hydrate()" : "render()"; - break; - } + if (to !== null && enterEvent !== null) { + accumulateEnterLeaveListenersForEvent( + dispatchQueue, + enterEvent, + to, + common, + true + ); } } - -function createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, // TODO: We have several of these arguments that are conceptually part of the - // host config, but because they are passed in at runtime, we have to thread - // them through the root constructor. Perhaps we should put them all into a - // single type, like a DynamicHostConfig that is defined by the renderer. - identifierPrefix, - onRecoverableError, - transitionCallbacks +function accumulateEventHandleNonManagedNodeListeners( + reactEventType, + currentTarget, + inCapturePhase ) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - var root = new FiberRootNode( - containerInfo, - tag, - hydrate, - identifierPrefix, - onRecoverableError - ); + var listeners = []; + var eventListeners = getEventHandlerListeners(currentTarget); - { - root.hydrationCallbacks = hydrationCallbacks; + if (eventListeners !== null) { + eventListeners.forEach(function (entry) { + if (entry.type === reactEventType && entry.capture === inCapturePhase) { + listeners.push( + createDispatchListener(null, entry.callback, currentTarget) + ); + } + }); } - if (enableTransitionTracing) { - root.transitionCallbacks = transitionCallbacks; - } // Cyclic construction. This cheats the type system right now because - // stateNode is any. - - var uninitializedFiber = createHostRootFiber( - tag, - isStrictMode, - concurrentUpdatesByDefaultOverride - ); - root.current = uninitializedFiber; - uninitializedFiber.stateNode = root; + return listeners; +} +function getListenerSetKey(domEventName, capture) { + return domEventName + "__" + (capture ? "capture" : "bubble"); +} - { - var initialCache = createCache(); - retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily - // for newly mounted boundaries during a render. In general, the - // pooledCache is always cleared from the root at the end of a render: - // it is either released when render commits, or moved to an Offscreen - // component if rendering suspends. Because the lifetime of the pooled - // cache is distinct from the main memoizedState.cache, it must be - // retained separately. +// has this definition built-in. - root.pooledCache = initialCache; - retainCache(initialCache); - var initialState = { - element: initialChildren, - isDehydrated: hydrate, - cache: initialCache - }; - uninitializedFiber.memoizedState = initialState; - } +var hasScheduledReplayAttempt = false; // The queue of discrete events to be replayed. - initializeUpdateQueue(uninitializedFiber); - return root; -} +var queuedDiscreteEvents = []; // Indicates if any continuous event targets are non-null for early bailout. +// if the last target was dehydrated. -var ReactVersion = "18.3.0-www-classic-ef5e99b7"; +var queuedFocus = null; +var queuedDrag = null; +var queuedMouse = null; // For pointer events there can be one latest event per pointerId. -function createPortal$1( - children, - containerInfo, // TODO: figure out the API for cross-renderer implementation. - implementation -) { - var key = - arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; +var queuedPointers = new Map(); +var queuedPointerCaptures = new Map(); // We could consider replaying selectionchange and touchmoves too. - { - checkKeyStringCoercion(key); - } +var queuedExplicitHydrationTargets = []; +function hasQueuedDiscreteEvents() { + return queuedDiscreteEvents.length > 0; +} +var discreteReplayableEvents = [ + "mousedown", + "mouseup", + "touchcancel", + "touchend", + "touchstart", + "auxclick", + "dblclick", + "pointercancel", + "pointerdown", + "pointerup", + "dragend", + "dragstart", + "drop", + "compositionend", + "compositionstart", + "keydown", + "keypress", + "keyup", + "input", + "textInput", // Intentionally camelCase + "copy", + "cut", + "paste", + "click", + "change", + "contextmenu", + "reset", + "submit" +]; +function isDiscreteEventThatRequiresHydration(eventType) { + return discreteReplayableEvents.indexOf(eventType) > -1; +} +function createQueuedReplayableEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent +) { return { - // This tag allow us to uniquely identify this as a React Portal - $$typeof: REACT_PORTAL_TYPE, - key: key == null ? null : "" + key, - children: children, - containerInfo: containerInfo, - implementation: implementation + blockedOn: blockedOn, + domEventName: domEventName, + eventSystemFlags: eventSystemFlags, + nativeEvent: nativeEvent, + targetContainers: [targetContainer] }; } -// Might add PROFILE later. - -var didWarnAboutNestedUpdates; -var didWarnAboutFindNodeInStrictMode; - -{ - didWarnAboutNestedUpdates = false; - didWarnAboutFindNodeInStrictMode = {}; -} - -function getContextForSubtree(parentComponent) { - if (!parentComponent) { - return emptyContextObject; +function queueDiscreteEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent +) { + if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { + return; } - var fiber = get(parentComponent); - var parentContext = findCurrentUnmaskedContext(fiber); + var queuedEvent = createQueuedReplayableEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); + queuedDiscreteEvents.push(queuedEvent); - if (fiber.tag === ClassComponent) { - var Component = fiber.type; + if (queuedDiscreteEvents.length === 1) { + // If this was the first discrete event, we might be able to + // synchronously unblock it so that preventDefault still works. + while (queuedEvent.blockedOn !== null) { + var fiber = getInstanceFromNode(queuedEvent.blockedOn); - if (isContextProvider(Component)) { - return processChildContext(fiber, Component, parentContext); - } - } + if (fiber === null) { + break; + } - return parentContext; -} + attemptSynchronousHydration(fiber); -function findHostInstanceWithWarning(component, methodName) { - { - var fiber = get(component); + if (queuedEvent.blockedOn === null) { + // We got unblocked by hydration. Let's try again. + replayUnblockedEvents(); // If we're reblocked, on an inner boundary, we might need + // to attempt hydrating that one. - if (fiber === undefined) { - if (typeof component.render === "function") { - throw new Error("Unable to find node on an unmounted component."); + continue; } else { - var keys = Object.keys(component).join(","); - throw new Error( - "Argument appears to not be a ReactComponent. Keys: " + keys - ); + // We're still blocked from hydration, we have to give up + // and replay later. + break; } } + } +} // Resets the replaying for this type of continuous event to no event. - var hostFiber = findCurrentHostFiber(fiber); +function clearIfContinuousEvent(domEventName, nativeEvent) { + switch (domEventName) { + case "focusin": + case "focusout": + queuedFocus = null; + break; - if (hostFiber === null) { - return null; + case "dragenter": + case "dragleave": + queuedDrag = null; + break; + + case "mouseover": + case "mouseout": + queuedMouse = null; + break; + + case "pointerover": + case "pointerout": { + var pointerId = nativeEvent.pointerId; + queuedPointers.delete(pointerId); + break; } - if (hostFiber.mode & StrictLegacyMode) { - var componentName = getComponentNameFromFiber(fiber) || "Component"; + case "gotpointercapture": + case "lostpointercapture": { + var _pointerId = nativeEvent.pointerId; + queuedPointerCaptures.delete(_pointerId); + break; + } + } +} - if (!didWarnAboutFindNodeInStrictMode[componentName]) { - didWarnAboutFindNodeInStrictMode[componentName] = true; - var previousFiber = current; +function accumulateOrCreateContinuousQueuedReplayableEvent( + existingQueuedEvent, + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent +) { + if ( + existingQueuedEvent === null || + existingQueuedEvent.nativeEvent !== nativeEvent + ) { + var queuedEvent = createQueuedReplayableEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); - try { - setCurrentFiber(hostFiber); + if (blockedOn !== null) { + var fiber = getInstanceFromNode(blockedOn); - if (fiber.mode & StrictLegacyMode) { - error( - "%s is deprecated in StrictMode. " + - "%s was passed an instance of %s which is inside StrictMode. " + - "Instead, add a ref directly to the element you want to reference. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-find-node", - methodName, - methodName, - componentName - ); - } else { - error( - "%s is deprecated in StrictMode. " + - "%s was passed an instance of %s which renders StrictMode children. " + - "Instead, add a ref directly to the element you want to reference. " + - "Learn more about using refs safely here: " + - "https://reactjs.org/link/strict-mode-find-node", - methodName, - methodName, - componentName - ); - } - } finally { - // Ideally this should reset to previous but this shouldn't be called in - // render and there's another warning for that anyway. - if (previousFiber) { - setCurrentFiber(previousFiber); - } else { - resetCurrentFiber(); - } - } + if (fiber !== null) { + // Attempt to increase the priority of this target. + attemptContinuousHydration(fiber); } } - return getPublicInstance(hostFiber.stateNode); + return queuedEvent; + } // If we have already queued this exact event, then it's because + // the different event systems have different DOM event listeners. + // We can accumulate the flags, and the targetContainers, and + // store a single event to be replayed. + + existingQueuedEvent.eventSystemFlags |= eventSystemFlags; + var targetContainers = existingQueuedEvent.targetContainers; + + if ( + targetContainer !== null && + targetContainers.indexOf(targetContainer) === -1 + ) { + targetContainers.push(targetContainer); } -} -function createContainer( - containerInfo, - tag, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onRecoverableError, - transitionCallbacks -) { - var hydrate = false; - var initialChildren = null; - return createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onRecoverableError, - transitionCallbacks - ); + return existingQueuedEvent; } -function createHydrationContainer( - initialChildren, // TODO: Remove `callback` when we delete legacy mode. - callback, - containerInfo, - tag, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onRecoverableError, - transitionCallbacks + +function queueIfContinuousEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent ) { - var hydrate = true; - var root = createFiberRoot( - containerInfo, - tag, - hydrate, - initialChildren, - hydrationCallbacks, - isStrictMode, - concurrentUpdatesByDefaultOverride, - identifierPrefix, - onRecoverableError, - transitionCallbacks - ); // TODO: Move this to FiberRoot constructor + // These set relatedTarget to null because the replayed event will be treated as if we + // moved from outside the window (no target) onto the target once it hydrates. + // Instead of mutating we could clone the event. + switch (domEventName) { + case "focusin": { + var focusEvent = nativeEvent; + queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent( + queuedFocus, + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + focusEvent + ); + return true; + } + + case "dragenter": { + var dragEvent = nativeEvent; + queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent( + queuedDrag, + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + dragEvent + ); + return true; + } + + case "mouseover": { + var mouseEvent = nativeEvent; + queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent( + queuedMouse, + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + mouseEvent + ); + return true; + } + + case "pointerover": { + var pointerEvent = nativeEvent; + var pointerId = pointerEvent.pointerId; + queuedPointers.set( + pointerId, + accumulateOrCreateContinuousQueuedReplayableEvent( + queuedPointers.get(pointerId) || null, + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + pointerEvent + ) + ); + return true; + } + + case "gotpointercapture": { + var _pointerEvent = nativeEvent; + var _pointerId2 = _pointerEvent.pointerId; + queuedPointerCaptures.set( + _pointerId2, + accumulateOrCreateContinuousQueuedReplayableEvent( + queuedPointerCaptures.get(_pointerId2) || null, + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + _pointerEvent + ) + ); + return true; + } + } - root.context = getContextForSubtree(null); // Schedule the initial render. In a hydration root, this is different from - // a regular update because the initial render must match was was rendered - // on the server. - // NOTE: This update intentionally doesn't have a payload. We're only using - // the update to schedule work on the root fiber (and, for legacy roots, to - // enqueue the callback if one is provided). + return false; +} // Check if this target is unblocked. Returns true if it's unblocked. - var current = root.current; - var lane = requestUpdateLane(current); - var update = createUpdate(lane); - update.callback = - callback !== undefined && callback !== null ? callback : null; - var eventTime = requestEventTime(); - enqueueUpdate(current, update, lane); - scheduleInitialHydrationOnRoot(root, lane, eventTime); - return root; -} -function updateContainer(element, container, parentComponent, callback) { - { - onScheduleRoot(container, element); - } +function attemptExplicitHydrationTarget(queuedTarget) { + // TODO: This function shares a lot of logic with findInstanceBlockingEvent. + // Try to unify them. It's a bit tricky since it would require two return + // values. + var targetInst = getClosestInstanceFromNode(queuedTarget.target); - var current$1 = container.current; - var lane = requestUpdateLane(current$1); + if (targetInst !== null) { + var nearestMounted = getNearestMountedFiber(targetInst); - if (enableSchedulingProfiler) { - markRenderScheduled(lane); - } + if (nearestMounted !== null) { + var tag = nearestMounted.tag; - var context = getContextForSubtree(parentComponent); + if (tag === SuspenseComponent) { + var instance = getSuspenseInstanceFromFiber(nearestMounted); - if (container.context === null) { - container.context = context; - } else { - container.pendingContext = context; - } + if (instance !== null) { + // We're blocked on hydrating this boundary. + // Increase its priority. + queuedTarget.blockedOn = instance; + runWithPriority(queuedTarget.priority, function () { + attemptHydrationAtCurrentPriority(nearestMounted); + }); + return; + } + } else if (tag === HostRoot) { + var root = nearestMounted.stateNode; - { - if (isRendering && current !== null && !didWarnAboutNestedUpdates) { - didWarnAboutNestedUpdates = true; + if (isRootDehydrated(root)) { + queuedTarget.blockedOn = getContainerFromFiber(nearestMounted); // We don't currently have a way to increase the priority of + // a root other than sync. - error( - "Render methods should be a pure function of props and state; " + - "triggering nested component updates from render is not allowed. " + - "If necessary, trigger nested updates in componentDidUpdate.\n\n" + - "Check the render method of %s.", - getComponentNameFromFiber(current) || "Unknown" - ); + return; + } + } } } - var update = createUpdate(lane); // Caution: React DevTools currently depends on this property - // being called "element". + queuedTarget.blockedOn = null; +} - update.payload = { - element: element +function queueExplicitHydrationTarget(target) { + // TODO: This will read the priority if it's dispatched by the React + // event system but not native events. Should read window.event.type, like + // we do for updates (getCurrentEventPriority). + var updatePriority = getCurrentUpdatePriority(); + var queuedTarget = { + blockedOn: null, + target: target, + priority: updatePriority }; - callback = callback === undefined ? null : callback; + var i = 0; - if (callback !== null) { - { - if (typeof callback !== "function") { - error( - "render(...): Expected the last optional `callback` argument to be a " + - "function. Instead received: %s.", - callback - ); - } + for (; i < queuedExplicitHydrationTargets.length; i++) { + // Stop once we hit the first target with lower priority than + if ( + !isHigherEventPriority( + updatePriority, + queuedExplicitHydrationTargets[i].priority + ) + ) { + break; } - - update.callback = callback; } - var root = enqueueUpdate(current$1, update, lane); + queuedExplicitHydrationTargets.splice(i, 0, queuedTarget); - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, current$1, lane, eventTime); - entangleTransitions(root, current$1, lane); + if (i === 0) { + attemptExplicitHydrationTarget(queuedTarget); } - - return lane; } -function getPublicRootInstance(container) { - var containerFiber = container.current; - if (!containerFiber.child) { - return null; +function attemptReplayContinuousQueuedEvent(queuedEvent) { + if (queuedEvent.blockedOn !== null) { + return false; } - switch (containerFiber.child.tag) { - case HostSingleton: - case HostComponent: - return getPublicInstance(containerFiber.child.stateNode); + var targetContainers = queuedEvent.targetContainers; - default: - return containerFiber.child.stateNode; + while (targetContainers.length > 0) { + var targetContainer = targetContainers[0]; + var nextBlockedOn = findInstanceBlockingEvent( + queuedEvent.domEventName, + queuedEvent.eventSystemFlags, + targetContainer, + queuedEvent.nativeEvent + ); + + if (nextBlockedOn === null) { + if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { + var nativeEvent = queuedEvent.nativeEvent; + var nativeEventClone = new nativeEvent.constructor( + nativeEvent.type, + nativeEvent + ); + setReplayingEvent(nativeEventClone); + nativeEvent.target.dispatchEvent(nativeEventClone); + resetReplayingEvent(); + } else { + setReplayingEvent(queuedEvent.nativeEvent); + dispatchEventForPluginEventSystem( + queuedEvent.domEventName, + queuedEvent.eventSystemFlags, + queuedEvent.nativeEvent, + return_targetInst, + targetContainer + ); + resetReplayingEvent(); + } + } else { + // We're still blocked. Try again later. + var fiber = getInstanceFromNode(nextBlockedOn); + + if (fiber !== null) { + attemptContinuousHydration(fiber); + } + + queuedEvent.blockedOn = nextBlockedOn; + return false; + } // This target container was successfully dispatched. Try the next. + + targetContainers.shift(); } + + return true; } -function attemptSynchronousHydration(fiber) { - switch (fiber.tag) { - case HostRoot: { - var root = fiber.stateNode; - if (isRootDehydrated(root)) { - // Flush the first scheduled "update". - var lanes = getHighestPriorityPendingLanes(root); - flushRoot(root, lanes); - } +function attemptReplayContinuousQueuedEventInMap(queuedEvent, key, map) { + if (attemptReplayContinuousQueuedEvent(queuedEvent)) { + map.delete(key); + } +} - break; - } +function replayUnblockedEvents() { + hasScheduledReplayAttempt = false; - case SuspenseComponent: { - flushSync$1(function () { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (!enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { + // First replay discrete events. + while (queuedDiscreteEvents.length > 0) { + var nextDiscreteEvent = queuedDiscreteEvents[0]; - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, SyncLane, eventTime); + if (nextDiscreteEvent.blockedOn !== null) { + // We're still blocked. + // Increase the priority of this boundary to unblock + // the next discrete event. + var fiber = getInstanceFromNode(nextDiscreteEvent.blockedOn); + + if (fiber !== null) { + attemptDiscreteHydration(fiber); } - }); // If we're still blocked after this, we need to increase - // the priority of any promises resolving within this - // boundary so that they next attempt also has higher pri. - var retryLane = SyncLane; - markRetryLaneIfNotHydrated(fiber, retryLane); - break; + break; + } + + var targetContainers = nextDiscreteEvent.targetContainers; + + while (targetContainers.length > 0) { + var targetContainer = targetContainers[0]; + var nextBlockedOn = findInstanceBlockingEvent( + nextDiscreteEvent.domEventName, + nextDiscreteEvent.eventSystemFlags, + targetContainer, + nextDiscreteEvent.nativeEvent + ); + + if (nextBlockedOn === null) { + // This whole function is in !enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay, + // so we don't need the new replay behavior code branch. + setReplayingEvent(nextDiscreteEvent.nativeEvent); + dispatchEventForPluginEventSystem( + nextDiscreteEvent.domEventName, + nextDiscreteEvent.eventSystemFlags, + nextDiscreteEvent.nativeEvent, + return_targetInst, + targetContainer + ); + resetReplayingEvent(); + } else { + // We're still blocked. Try again later. + nextDiscreteEvent.blockedOn = nextBlockedOn; + break; + } // This target container was successfully dispatched. Try the next. + + targetContainers.shift(); + } + + if (nextDiscreteEvent.blockedOn === null) { + // We've successfully replayed the first event. Let's try the next one. + queuedDiscreteEvents.shift(); + } } + } // Next replay any continuous events. + + if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) { + queuedFocus = null; } -} -function markRetryLaneImpl(fiber, retryLane) { - var suspenseState = fiber.memoizedState; + if (queuedDrag !== null && attemptReplayContinuousQueuedEvent(queuedDrag)) { + queuedDrag = null; + } - if (suspenseState !== null && suspenseState.dehydrated !== null) { - suspenseState.retryLane = higherPriorityLane( - suspenseState.retryLane, - retryLane - ); + if (queuedMouse !== null && attemptReplayContinuousQueuedEvent(queuedMouse)) { + queuedMouse = null; } -} // Increases the priority of thenables when they resolve within this boundary. -function markRetryLaneIfNotHydrated(fiber, retryLane) { - markRetryLaneImpl(fiber, retryLane); - var alternate = fiber.alternate; + queuedPointers.forEach(attemptReplayContinuousQueuedEventInMap); + queuedPointerCaptures.forEach(attemptReplayContinuousQueuedEventInMap); +} - if (alternate) { - markRetryLaneImpl(alternate, retryLane); +function scheduleCallbackIfUnblocked(queuedEvent, unblocked) { + if (queuedEvent.blockedOn === unblocked) { + queuedEvent.blockedOn = null; + + if (!hasScheduledReplayAttempt) { + hasScheduledReplayAttempt = true; // Schedule a callback to attempt replaying as many events as are + // now unblocked. This first might not actually be unblocked yet. + // We could check it early to avoid scheduling an unnecessary callback. + + Scheduler.unstable_scheduleCallback( + Scheduler.unstable_NormalPriority, + replayUnblockedEvents + ); + } } } -function attemptDiscreteHydration(fiber) { - if (fiber.tag !== SuspenseComponent) { - // We ignore HostRoots here because we can't increase - // their priority and they should not suspend on I/O, - // since you have to wrap anything that might suspend in - // Suspense. - return; - } +function retryIfBlockedOn(unblocked) { + // Mark anything that was blocked on this as no longer blocked + // and eligible for a replay. + if (queuedDiscreteEvents.length > 0) { + scheduleCallbackIfUnblocked(queuedDiscreteEvents[0], unblocked); // This is a exponential search for each boundary that commits. I think it's + // worth it because we expect very few discrete events to queue up and once + // we are actually fully unblocked it will be fast to replay them. - var lane = SyncLane; - var root = enqueueConcurrentRenderForLane(fiber, lane); + for (var i = 1; i < queuedDiscreteEvents.length; i++) { + var queuedEvent = queuedDiscreteEvents[i]; - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); + if (queuedEvent.blockedOn === unblocked) { + queuedEvent.blockedOn = null; + } + } } - markRetryLaneIfNotHydrated(fiber, lane); -} -function attemptContinuousHydration(fiber) { - if (fiber.tag !== SuspenseComponent) { - // We ignore HostRoots here because we can't increase - // their priority and they should not suspend on I/O, - // since you have to wrap anything that might suspend in - // Suspense. - return; + if (queuedFocus !== null) { + scheduleCallbackIfUnblocked(queuedFocus, unblocked); } - var lane = SelectiveHydrationLane; - var root = enqueueConcurrentRenderForLane(fiber, lane); - - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); + if (queuedDrag !== null) { + scheduleCallbackIfUnblocked(queuedDrag, unblocked); } - markRetryLaneIfNotHydrated(fiber, lane); -} -function attemptHydrationAtCurrentPriority(fiber) { - if (fiber.tag !== SuspenseComponent) { - // We ignore HostRoots here because we can't increase - // their priority other than synchronously flush it. - return; + if (queuedMouse !== null) { + scheduleCallbackIfUnblocked(queuedMouse, unblocked); } - var lane = requestUpdateLane(fiber); - var root = enqueueConcurrentRenderForLane(fiber, lane); + var unblock = function (queuedEvent) { + return scheduleCallbackIfUnblocked(queuedEvent, unblocked); + }; - if (root !== null) { - var eventTime = requestEventTime(); - scheduleUpdateOnFiber(root, fiber, lane, eventTime); - } + queuedPointers.forEach(unblock); + queuedPointerCaptures.forEach(unblock); - markRetryLaneIfNotHydrated(fiber, lane); -} -function findHostInstanceWithNoPortals(fiber) { - var hostFiber = findCurrentHostFiberWithNoPortals(fiber); + for (var _i = 0; _i < queuedExplicitHydrationTargets.length; _i++) { + var queuedTarget = queuedExplicitHydrationTargets[_i]; - if (hostFiber === null) { - return null; + if (queuedTarget.blockedOn === unblocked) { + queuedTarget.blockedOn = null; + } } - return getPublicInstance(hostFiber.stateNode); -} + while (queuedExplicitHydrationTargets.length > 0) { + var nextExplicitTarget = queuedExplicitHydrationTargets[0]; -var shouldErrorImpl = function (fiber) { - return null; -}; + if (nextExplicitTarget.blockedOn !== null) { + // We're still blocked. + break; + } else { + attemptExplicitHydrationTarget(nextExplicitTarget); -function shouldError(fiber) { - return shouldErrorImpl(fiber); + if (nextExplicitTarget.blockedOn === null) { + // We're unblocked. + queuedExplicitHydrationTargets.shift(); + } + } + } } -var shouldSuspendImpl = function (fiber) { - return false; -}; +var ReactCurrentBatchConfig = ReactSharedInternals.ReactCurrentBatchConfig; // TODO: can we stop exporting these? -function shouldSuspend(fiber) { - return shouldSuspendImpl(fiber); +var _enabled = true; // This is exported in FB builds for use by legacy FB layer infra. +// We'd like to remove this but it's not clear if this is safe. + +function setEnabled(enabled) { + _enabled = !!enabled; } -var overrideHookState = null; -var overrideHookStateDeletePath = null; -var overrideHookStateRenamePath = null; -var overrideProps = null; -var overridePropsDeletePath = null; -var overridePropsRenamePath = null; -var scheduleUpdate = null; -var setErrorHandler = null; -var setSuspenseHandler = null; +function isEnabled() { + return _enabled; +} +function createEventListenerWrapperWithPriority( + targetContainer, + domEventName, + eventSystemFlags +) { + var eventPriority = getEventPriority(domEventName); + var listenerWrapper; -{ - var copyWithDeleteImpl = function (obj, path, index) { - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + switch (eventPriority) { + case DiscreteEventPriority: + listenerWrapper = dispatchDiscreteEvent; + break; - if (index + 1 === path.length) { - if (isArray(updated)) { - updated.splice(key, 1); - } else { - delete updated[key]; - } + case ContinuousEventPriority: + listenerWrapper = dispatchContinuousEvent; + break; - return updated; - } // $FlowFixMe number or string is fine here + case DefaultEventPriority: + default: + listenerWrapper = dispatchEvent; + break; + } - updated[key] = copyWithDeleteImpl(obj[key], path, index + 1); - return updated; - }; + return listenerWrapper.bind( + null, + domEventName, + eventSystemFlags, + targetContainer + ); +} - var copyWithDelete = function (obj, path) { - return copyWithDeleteImpl(obj, path, 0); - }; +function dispatchDiscreteEvent( + domEventName, + eventSystemFlags, + container, + nativeEvent +) { + var previousPriority = getCurrentUpdatePriority(); + var prevTransition = ReactCurrentBatchConfig.transition; + ReactCurrentBatchConfig.transition = null; - var copyWithRenameImpl = function (obj, oldPath, newPath, index) { - var oldKey = oldPath[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); + try { + setCurrentUpdatePriority(DiscreteEventPriority); + dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig.transition = prevTransition; + } +} - if (index + 1 === oldPath.length) { - var newKey = newPath[index]; // $FlowFixMe number or string is fine here +function dispatchContinuousEvent( + domEventName, + eventSystemFlags, + container, + nativeEvent +) { + var previousPriority = getCurrentUpdatePriority(); + var prevTransition = ReactCurrentBatchConfig.transition; + ReactCurrentBatchConfig.transition = null; - updated[newKey] = updated[oldKey]; + try { + setCurrentUpdatePriority(ContinuousEventPriority); + dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); + } finally { + setCurrentUpdatePriority(previousPriority); + ReactCurrentBatchConfig.transition = prevTransition; + } +} + +function dispatchEvent( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent +) { + if (!_enabled) { + return; + } + + if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { + dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); + } else { + dispatchEventOriginal( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); + } +} - if (isArray(updated)) { - updated.splice(oldKey, 1); - } else { - delete updated[oldKey]; - } - } else { - // $FlowFixMe number or string is fine here - updated[oldKey] = copyWithRenameImpl( - // $FlowFixMe number or string is fine here - obj[oldKey], - oldPath, - newPath, - index + 1 - ); - } +function dispatchEventOriginal( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent +) { + // TODO: replaying capture phase events is currently broken + // because we used to do it during top-level native bubble handlers + // but now we use different bubble and capture handlers. + // In eager mode, we attach capture listeners early, so we need + // to filter them out until we fix the logic to handle them correctly. + var allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0; - return updated; - }; + if ( + allowReplay && + hasQueuedDiscreteEvents() && + isDiscreteEventThatRequiresHydration(domEventName) + ) { + // If we already have a queue of discrete events, and this is another discrete + // event, then we can't dispatch it regardless of its target, since they + // need to dispatch in order. + queueDiscreteEvent( + null, // Flags that we're not actually blocked on anything as far as we know. + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); + return; + } - var copyWithRename = function (obj, oldPath, newPath) { - if (oldPath.length !== newPath.length) { - warn("copyWithRename() expects paths of the same length"); + var blockedOn = findInstanceBlockingEvent( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); - return; - } else { - for (var i = 0; i < newPath.length - 1; i++) { - if (oldPath[i] !== newPath[i]) { - warn( - "copyWithRename() expects paths to be the same except for the deepest key" - ); + if (blockedOn === null) { + dispatchEventForPluginEventSystem( + domEventName, + eventSystemFlags, + nativeEvent, + return_targetInst, + targetContainer + ); - return; - } - } + if (allowReplay) { + clearIfContinuousEvent(domEventName, nativeEvent); } - return copyWithRenameImpl(obj, oldPath, newPath, 0); - }; + return; + } - var copyWithSetImpl = function (obj, path, index, value) { - if (index >= path.length) { - return value; + if (allowReplay) { + if (isDiscreteEventThatRequiresHydration(domEventName)) { + // This to be replayed later once the target is available. + queueDiscreteEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); + return; } - var key = path[index]; - var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe number or string is fine here - - updated[key] = copyWithSetImpl(obj[key], path, index + 1, value); - return updated; - }; + if ( + queueIfContinuousEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ) + ) { + return; + } // We need to clear only if we didn't queue because + // queueing is accumulative. - var copyWithSet = function (obj, path, value) { - return copyWithSetImpl(obj, path, 0, value); - }; + clearIfContinuousEvent(domEventName, nativeEvent); + } // This is not replayable so we'll invoke it but without a target, + // in case the event system needs to trace it. - var findHook = function (fiber, id) { - // For now, the "id" of stateful hooks is just the stateful hook index. - // This may change in the future with e.g. nested hooks. - var currentHook = fiber.memoizedState; + dispatchEventForPluginEventSystem( + domEventName, + eventSystemFlags, + nativeEvent, + null, + targetContainer + ); +} - while (currentHook !== null && id > 0) { - currentHook = currentHook.next; - id--; - } +function dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent +) { + var blockedOn = findInstanceBlockingEvent( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); - return currentHook; - }; // Support DevTools editable values for useState and useReducer. + if (blockedOn === null) { + dispatchEventForPluginEventSystem( + domEventName, + eventSystemFlags, + nativeEvent, + return_targetInst, + targetContainer + ); + clearIfContinuousEvent(domEventName, nativeEvent); + return; + } - overrideHookState = function (fiber, id, path, value) { - var hook = findHook(fiber, id); + if ( + queueIfContinuousEvent( + blockedOn, + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ) + ) { + nativeEvent.stopPropagation(); + return; + } // We need to clear only if we didn't queue because + // queueing is accumulative. - if (hook !== null) { - var newState = copyWithSet(hook.memoizedState, path, value); - hook.memoizedState = newState; - hook.baseState = newState; // We aren't actually adding an update to the queue, - // because there is no update we can add for useReducer hooks that won't trigger an error. - // (There's no appropriate action type for DevTools overrides.) - // As a result though, React will see the scheduled update as a noop and bailout. - // Shallow cloning props works as a workaround for now to bypass the bailout check. + clearIfContinuousEvent(domEventName, nativeEvent); - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if ( + eventSystemFlags & IS_CAPTURE_PHASE && + isDiscreteEventThatRequiresHydration(domEventName) + ) { + while (blockedOn !== null) { + var fiber = getInstanceFromNode(blockedOn); - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + if (fiber !== null) { + attemptSynchronousHydration(fiber); } - } - }; - - overrideHookStateDeletePath = function (fiber, id, path) { - var hook = findHook(fiber, id); - if (hook !== null) { - var newState = copyWithDelete(hook.memoizedState, path); - hook.memoizedState = newState; - hook.baseState = newState; // We aren't actually adding an update to the queue, - // because there is no update we can add for useReducer hooks that won't trigger an error. - // (There's no appropriate action type for DevTools overrides.) - // As a result though, React will see the scheduled update as a noop and bailout. - // Shallow cloning props works as a workaround for now to bypass the bailout check. + var nextBlockedOn = findInstanceBlockingEvent( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent + ); - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (nextBlockedOn === null) { + dispatchEventForPluginEventSystem( + domEventName, + eventSystemFlags, + nativeEvent, + return_targetInst, + targetContainer + ); + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + if (nextBlockedOn === blockedOn) { + break; } + + blockedOn = nextBlockedOn; } - }; - overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) { - var hook = findHook(fiber, id); + if (blockedOn !== null) { + nativeEvent.stopPropagation(); + } - if (hook !== null) { - var newState = copyWithRename(hook.memoizedState, oldPath, newPath); - hook.memoizedState = newState; - hook.baseState = newState; // We aren't actually adding an update to the queue, - // because there is no update we can add for useReducer hooks that won't trigger an error. - // (There's no appropriate action type for DevTools overrides.) - // As a result though, React will see the scheduled update as a noop and bailout. - // Shallow cloning props works as a workaround for now to bypass the bailout check. + return; + } // This is not replayable so we'll invoke it but without a target, + // in case the event system needs to trace it. - fiber.memoizedProps = assign({}, fiber.memoizedProps); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + dispatchEventForPluginEventSystem( + domEventName, + eventSystemFlags, + nativeEvent, + null, + targetContainer + ); +} - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - } - }; // Support DevTools props for function components, forwardRef, memo, host components, etc. +var return_targetInst = null; // Returns a SuspenseInstance or Container if it's blocked. +// The return_targetInst field above is conceptually part of the return value. - overrideProps = function (fiber, path, value) { - fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value); +function findInstanceBlockingEvent( + domEventName, + eventSystemFlags, + targetContainer, + nativeEvent +) { + // TODO: Warn if _enabled is false. + return_targetInst = null; + var nativeEventTarget = getEventTarget(nativeEvent); + var targetInst = getClosestInstanceFromNode(nativeEventTarget); - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + if (targetInst !== null) { + var nearestMounted = getNearestMountedFiber(targetInst); - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (nearestMounted === null) { + // This tree has been unmounted already. Dispatch without a target. + targetInst = null; + } else { + var tag = nearestMounted.tag; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - }; + if (tag === SuspenseComponent) { + var instance = getSuspenseInstanceFromFiber(nearestMounted); - overridePropsDeletePath = function (fiber, path) { - fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path); + if (instance !== null) { + // Queue the event to be replayed later. Abort dispatching since we + // don't want this event dispatched twice through the event system. + // TODO: If this is the first discrete event in the queue. Schedule an increased + // priority for this boundary. + return instance; + } // This shouldn't happen, something went wrong but to avoid blocking + // the whole system, dispatch the event without a target. + // TODO: Warn. - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + targetInst = null; + } else if (tag === HostRoot) { + var root = nearestMounted.stateNode; - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + if (isRootDehydrated(root)) { + // If this happens during a replay something went wrong and it might block + // the whole system. + return getContainerFromFiber(nearestMounted); + } - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); + targetInst = null; + } else if (nearestMounted !== targetInst) { + // If we get an event (ex: img onload) before committing that + // component's mount, ignore it for now (that is, treat it as if it was an + // event on a non-React tree). We might also consider queueing events and + // dispatching them after the mount. + targetInst = null; + } } - }; + } - overridePropsRenamePath = function (fiber, oldPath, newPath) { - fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath); + return_targetInst = targetInst; // We're not blocked on anything. - if (fiber.alternate) { - fiber.alternate.pendingProps = fiber.pendingProps; - } + return null; +} +function getEventPriority(domEventName) { + switch (domEventName) { + // Used by SimpleEventPlugin: + case "cancel": + case "click": + case "close": + case "contextmenu": + case "copy": + case "cut": + case "auxclick": + case "dblclick": + case "dragend": + case "dragstart": + case "drop": + case "focusin": + case "focusout": + case "input": + case "invalid": + case "keydown": + case "keypress": + case "keyup": + case "mousedown": + case "mouseup": + case "paste": + case "pause": + case "play": + case "pointercancel": + case "pointerdown": + case "pointerup": + case "ratechange": + case "reset": + case "resize": + case "seeked": + case "submit": + case "touchcancel": + case "touchend": + case "touchstart": + case "volumechange": // Used by polyfills: + // eslint-disable-next-line no-fallthrough - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + case "change": + case "selectionchange": + case "textInput": + case "compositionstart": + case "compositionend": + case "compositionupdate": // Only enableCreateEventHandleAPI: + // eslint-disable-next-line no-fallthrough - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - }; + case "beforeblur": + case "afterblur": // Not used by React but could be by user code: + // eslint-disable-next-line no-fallthrough - scheduleUpdate = function (fiber) { - var root = enqueueConcurrentRenderForLane(fiber, SyncLane); + case "beforeinput": + case "blur": + case "fullscreenchange": + case "focus": + case "hashchange": + case "popstate": + case "select": + case "selectstart": + return DiscreteEventPriority; - if (root !== null) { - scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp); - } - }; + case "drag": + case "dragenter": + case "dragexit": + case "dragleave": + case "dragover": + case "mousemove": + case "mouseout": + case "mouseover": + case "pointermove": + case "pointerout": + case "pointerover": + case "scroll": + case "toggle": + case "touchmove": + case "wheel": // Not used by React but could be by user code: + // eslint-disable-next-line no-fallthrough - setErrorHandler = function (newShouldErrorImpl) { - shouldErrorImpl = newShouldErrorImpl; - }; + case "mouseenter": + case "mouseleave": + case "pointerenter": + case "pointerleave": + return ContinuousEventPriority; - setSuspenseHandler = function (newShouldSuspendImpl) { - shouldSuspendImpl = newShouldSuspendImpl; - }; -} + case "message": { + // We might be in the Scheduler callback. + // Eventually this mechanism will be replaced by a check + // of the current priority on the native scheduler. + var schedulerPriority = getCurrentPriorityLevel(); -function findHostInstanceByFiber(fiber) { - var hostFiber = findCurrentHostFiber(fiber); + switch (schedulerPriority) { + case ImmediatePriority: + return DiscreteEventPriority; - if (hostFiber === null) { - return null; - } + case UserBlockingPriority: + return ContinuousEventPriority; - return hostFiber.stateNode; -} + case NormalPriority$1: + case LowPriority: + // TODO: Handle LowSchedulerPriority, somehow. Maybe the same lane as hydration. + return DefaultEventPriority; -function emptyFindFiberByHostInstance(instance) { - return null; -} + case IdlePriority: + return IdleEventPriority; -function getCurrentFiberForDevTools() { - return current; -} + default: + return DefaultEventPriority; + } + } -function injectIntoDevTools(devToolsConfig) { - var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; - var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; - return injectInternals({ - bundleType: devToolsConfig.bundleType, - version: devToolsConfig.version, - rendererPackageName: devToolsConfig.rendererPackageName, - rendererConfig: devToolsConfig.rendererConfig, - overrideHookState: overrideHookState, - overrideHookStateDeletePath: overrideHookStateDeletePath, - overrideHookStateRenamePath: overrideHookStateRenamePath, - overrideProps: overrideProps, - overridePropsDeletePath: overridePropsDeletePath, - overridePropsRenamePath: overridePropsRenamePath, - setErrorHandler: setErrorHandler, - setSuspenseHandler: setSuspenseHandler, - scheduleUpdate: scheduleUpdate, - currentDispatcherRef: ReactCurrentDispatcher, - findHostInstanceByFiber: findHostInstanceByFiber, - findFiberByHostInstance: - findFiberByHostInstance || emptyFindFiberByHostInstance, - // React Refresh - findHostInstancesForRefresh: findHostInstancesForRefresh, - scheduleRefresh: scheduleRefresh, - scheduleRoot: scheduleRoot, - setRefreshHandler: setRefreshHandler, - // Enables DevTools to append owner stacks to error messages in DEV mode. - getCurrentFiber: getCurrentFiberForDevTools, - // Enables DevTools to detect reconciler version rather than renderer version - // which may not match for third party renderers. - reconcilerVersion: ReactVersion - }); + default: + return DefaultEventPriority; + } } var Dispatcher = Internals.Dispatcher; @@ -44116,13 +44059,6 @@ function preinit() { // so we favor silent bailout over warning or erroring. } -setAttemptSynchronousHydration(attemptSynchronousHydration); -setAttemptDiscreteHydration(attemptDiscreteHydration); -setAttemptContinuousHydration(attemptContinuousHydration); -setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority); -setGetCurrentUpdatePriority(getCurrentUpdatePriority$1); -setAttemptHydrationAtPriority(runWithPriority); - { if ( typeof Map !== "function" || // $FlowFixMe Flow incorrectly thinks Map has no prototype @@ -44140,9 +44076,6 @@ setAttemptHydrationAtPriority(runWithPriority); } } -setRestoreImplementation(restoreControlledState); -setBatchingImplementation(batchedUpdates, discreteUpdates, flushSync$1); - function createPortal(children, container) { var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; @@ -44219,7 +44152,7 @@ Internals.Events = [ getFiberCurrentPropsFromNode, enqueueStateRestore, restoreStateIfNeeded, - batchedUpdates + batchedUpdates$1 ]; var foundDevTools = injectIntoDevTools({ findFiberByHostInstance: getClosestInstanceFromNode, @@ -44274,7 +44207,7 @@ exports.preinit = preinit; exports.preload = preload; exports.render = render; exports.unmountComponentAtNode = unmountComponentAtNode; -exports.unstable_batchedUpdates = batchedUpdates; +exports.unstable_batchedUpdates = batchedUpdates$1; exports.unstable_createEventHandle = createEventHandle; exports.unstable_flushControlled = flushControlled; exports.unstable_renderSubtreeIntoContainer = renderSubtreeIntoContainer; diff --git a/compiled/facebook-www/ReactDOM-dev.modern.js b/compiled/facebook-www/ReactDOM-dev.modern.js index de04fbe9d85b6..8d577f09ce6f5 100644 --- a/compiled/facebook-www/ReactDOM-dev.modern.js +++ b/compiled/facebook-www/ReactDOM-dev.modern.js @@ -141,6 +141,7 @@ var dynamicFeatureFlags = require("ReactFeatureFlags"); var disableInputAttributeSyncing = dynamicFeatureFlags.disableInputAttributeSyncing, + disableIEWorkarounds = dynamicFeatureFlags.disableIEWorkarounds, enableTrustedTypesIntegration = dynamicFeatureFlags.enableTrustedTypesIntegration, replayFailedUnitOfWorkWithInvokeGuardedCallback = @@ -5109,7 +5110,6 @@ function getEventTarget(nativeEvent) { return target.nodeType === TEXT_NODE ? target.parentNode : target; } -var restoreImpl = null; var restoreTarget = null; var restoreQueue = null; @@ -5123,24 +5123,18 @@ function restoreStateOfTarget(target) { return; } - if (typeof restoreImpl !== "function") { - throw new Error( - "setRestoreImplementation() needs to be called to handle a target for controlled " + - "events. This error is likely caused by a bug in React. Please file an issue." - ); - } - var stateNode = internalInstance.stateNode; // Guard against Fiber being unmounted. if (stateNode) { var props = getFiberCurrentPropsFromNode(stateNode); - restoreImpl(internalInstance.stateNode, internalInstance.type, props); + restoreControlledState( + internalInstance.stateNode, + internalInstance.type, + props + ); } } -function setRestoreImplementation(impl) { - restoreImpl = impl; -} function enqueueStateRestore(target) { if (restoreTarget) { if (restoreQueue) { @@ -5173,256 +5167,6 @@ function restoreStateIfNeeded() { } } -// the renderer. Such as when we're dispatching events or if third party -// libraries need to call batchedUpdates. Eventually, this API will go away when -// everything is batched by default. We'll then have a similar API to opt-out of -// scheduled work and instead do synchronous work. -// Defaults - -var batchedUpdatesImpl = function (fn, bookkeeping) { - return fn(bookkeeping); -}; - -var flushSyncImpl = function () {}; - -var isInsideEventHandler = false; - -function finishEventHandler() { - // Here we wait until all updates have propagated, which is important - // when using controlled components within layers: - // https://github.com/facebook/react/issues/1698 - // Then we restore state of any controlled component. - var controlledComponentsHavePendingUpdates = needsStateRestore(); - - if (controlledComponentsHavePendingUpdates) { - // If a controlled event was fired, we may need to restore the state of - // the DOM node back to the controlled value. This is necessary when React - // bails out of the update without touching the DOM. - // TODO: Restore state in the microtask, after the discrete updates flush, - // instead of early flushing them here. - flushSyncImpl(); - restoreStateIfNeeded(); - } -} - -function batchedUpdates$1(fn, a, b) { - if (isInsideEventHandler) { - // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. - return fn(a, b); - } - - isInsideEventHandler = true; - - try { - return batchedUpdatesImpl(fn, a, b); - } finally { - isInsideEventHandler = false; - finishEventHandler(); - } -} // TODO: Replace with flushSync -function setBatchingImplementation( - _batchedUpdatesImpl, - _discreteUpdatesImpl, - _flushSyncImpl -) { - batchedUpdatesImpl = _batchedUpdatesImpl; - flushSyncImpl = _flushSyncImpl; -} - -function isInteractive(tag) { - return ( - tag === "button" || - tag === "input" || - tag === "select" || - tag === "textarea" - ); -} - -function shouldPreventMouseEvent(name, type, props) { - switch (name) { - case "onClick": - case "onClickCapture": - case "onDoubleClick": - case "onDoubleClickCapture": - case "onMouseDown": - case "onMouseDownCapture": - case "onMouseMove": - case "onMouseMoveCapture": - case "onMouseUp": - case "onMouseUpCapture": - case "onMouseEnter": - return !!(props.disabled && isInteractive(type)); - - default: - return false; - } -} -/** - * @param {object} inst The instance, which is the source of events. - * @param {string} registrationName Name of listener (e.g. `onClick`). - * @return {?function} The stored callback. - */ - -function getListener(inst, registrationName) { - var stateNode = inst.stateNode; - - if (stateNode === null) { - // Work in progress (ex: onload events in incremental mode). - return null; - } - - var props = getFiberCurrentPropsFromNode(stateNode); - - if (props === null) { - // Work in progress. - return null; - } - - var listener = props[registrationName]; - - if (shouldPreventMouseEvent(registrationName, inst.type, props)) { - return null; - } - - if (listener && typeof listener !== "function") { - throw new Error( - "Expected `" + - registrationName + - "` listener to be a function, instead got a value of `" + - typeof listener + - "` type." - ); - } - - return listener; -} - -var passiveBrowserEventsSupported = false; // Check if browser support events with passive listeners -// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support - -if (canUseDOM) { - try { - var options = {}; - Object.defineProperty(options, "passive", { - get: function () { - passiveBrowserEventsSupported = true; - } - }); - window.addEventListener("test", options, options); - window.removeEventListener("test", options, options); - } catch (e) { - passiveBrowserEventsSupported = false; - } -} - -// Provided by www -var ReactFbErrorUtils = require("ReactFbErrorUtils"); - -if (typeof ReactFbErrorUtils.invokeGuardedCallback !== "function") { - throw new Error( - "Expected ReactFbErrorUtils.invokeGuardedCallback to be a function." - ); -} - -function invokeGuardedCallbackImpl(name, func, context, a, b, c, d, e, f) { - // This will call `this.onError(err)` if an error was caught. - ReactFbErrorUtils.invokeGuardedCallback.apply(this, arguments); -} - -var hasError = false; -var caughtError = null; // Used by event system to capture/rethrow the first error. - -var hasRethrowError = false; -var rethrowError = null; -var reporter = { - onError: function (error) { - hasError = true; - caughtError = error; - } -}; -/** - * 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 - */ - -function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) { - hasError = false; - caughtError = null; - invokeGuardedCallbackImpl.apply(reporter, arguments); -} -/** - * 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 - */ - -function invokeGuardedCallbackAndCatchFirstError( - name, - func, - context, - a, - b, - c, - d, - e, - f -) { - invokeGuardedCallback.apply(this, arguments); - - if (hasError) { - var error = clearCaughtError(); - - if (!hasRethrowError) { - hasRethrowError = true; - rethrowError = error; - } - } -} -/** - * During execution of guarded functions we will capture the first error which - * we will rethrow to be handled by the top level error handler. - */ - -function rethrowCaughtError() { - if (hasRethrowError) { - var error = rethrowError; - hasRethrowError = false; - rethrowError = null; - throw error; - } -} -function hasCaughtError() { - return hasError; -} -function clearCaughtError() { - if (hasError) { - var error = caughtError; - hasError = false; - caughtError = null; - return error; - } else { - throw new Error( - "clearCaughtError was called but no error was captured. This error " + - "is likely caused by a bug in React. Please file an issue." - ); - } -} - /** * `ReactInstanceMap` maintains a mapping from a public facing stateful * instance (key) and the internal representation (value). This allows public @@ -5879,477 +5623,206 @@ function doesFiberContain(parentFiber, childFiber) { return false; } -// This module only exists as an ESM wrapper around the external CommonJS -var scheduleCallback$2 = Scheduler.unstable_scheduleCallback; -var cancelCallback$1 = Scheduler.unstable_cancelCallback; -var shouldYield = Scheduler.unstable_shouldYield; -var requestPaint = Scheduler.unstable_requestPaint; -var now$1 = Scheduler.unstable_now; -var getCurrentPriorityLevel = Scheduler.unstable_getCurrentPriorityLevel; -var ImmediatePriority = Scheduler.unstable_ImmediatePriority; -var UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; -var NormalPriority$1 = Scheduler.unstable_NormalPriority; -var LowPriority = Scheduler.unstable_LowPriority; -var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* -// on scheduler/unstable_mock, which we'll need for internal testing - -var log$2 = Scheduler.log; -var unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue; +var loggedTypeFailures = {}; +var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; -var rendererID = null; -var injectedHook = null; -var injectedProfilingHooks = null; -var hasLoggedError = false; -var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; -function injectInternals(internals) { - if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { - // No DevTools - return false; +function setCurrentlyValidatingElement(element) { + { + if (element) { + var owner = element._owner; + var stack = describeUnknownElementTypeFrameInDEV( + element.type, + element._source, + owner ? owner.type : null + ); + ReactDebugCurrentFrame.setExtraStackFrame(stack); + } else { + ReactDebugCurrentFrame.setExtraStackFrame(null); + } } +} - var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; +function checkPropTypes(typeSpecs, values, location, componentName, element) { + { + // $FlowFixMe This is okay but Flow doesn't know it. + var has = Function.call.bind(hasOwnProperty); - 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; - } + for (var typeSpecName in typeSpecs) { + if (has(typeSpecs, typeSpecName)) { + var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to + // fail the render phase where it didn't fail before. So we log it. + // After these have been cleaned up, we'll let them throw. - if (!hook.supportsFiber) { - { - error( - "The installed version of React DevTools is too old and will not work " + - "with the current version of React. Please update React DevTools. " + - "https://reactjs.org/link/react-devtools" - ); - } // DevTools exists, even though it doesn't support Fiber. + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + if (typeof typeSpecs[typeSpecName] !== "function") { + // eslint-disable-next-line react-internal/prod-error-codes + var err = Error( + (componentName || "React class") + + ": " + + location + + " type `" + + typeSpecName + + "` is invalid; " + + "it must be a function, usually from the `prop-types` package, but received `" + + typeof typeSpecs[typeSpecName] + + "`." + + "This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`." + ); + err.name = "Invariant Violation"; + throw err; + } - return true; - } + error$1 = typeSpecs[typeSpecName]( + values, + typeSpecName, + componentName, + location, + null, + "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED" + ); + } catch (ex) { + error$1 = ex; + } - try { - if (enableSchedulingProfiler) { - // Conditionally inject these hooks only if Timeline profiler is supported by this build. - // This gives DevTools a way to feature detect that isn't tied to version number - // (since profiling and timeline are controlled by different feature flags). - internals = assign({}, internals, { - getLaneLabelMap: getLaneLabelMap, - injectProfilingHooks: injectProfilingHooks - }); - } + if (error$1 && !(error$1 instanceof Error)) { + setCurrentlyValidatingElement(element); - rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks. + error( + "%s: type specification of %s" + + " `%s` is invalid; the type checker " + + "function must return `null` or an `Error` but returned a %s. " + + "You may have forgotten to pass an argument to the type checker " + + "creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and " + + "shape all require an argument).", + componentName || "React class", + location, + typeSpecName, + typeof error$1 + ); - injectedHook = hook; - } catch (err) { - // Catch all errors because it is unsafe to throw during initialization. - { - error("React instrumentation encountered an error: %s.", err); - } - } + setCurrentlyValidatingElement(null); + } - if (hook.checkDCE) { - // This is the real DevTools. - return true; - } else { - // This is likely a hook installed by Fast Refresh runtime. - return false; - } -} -function onScheduleRoot(root, children) { - { - if ( - injectedHook && - typeof injectedHook.onScheduleFiberRoot === "function" - ) { - try { - injectedHook.onScheduleFiberRoot(rendererID, root, children); - } catch (err) { - if (!hasLoggedError) { - hasLoggedError = true; + if ( + error$1 instanceof Error && + !(error$1.message in loggedTypeFailures) + ) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error$1.message] = true; + setCurrentlyValidatingElement(element); - error("React instrumentation encountered an error: %s", err); + error("Failed %s type: %s", location, error$1.message); + + setCurrentlyValidatingElement(null); } } } } } -function onCommitRoot$1(root, eventPriority) { - if (injectedHook && typeof injectedHook.onCommitFiberRoot === "function") { - try { - var didError = (root.current.flags & DidCapture) === DidCapture; - - if (enableProfilerTimer) { - var schedulerPriority; - switch (eventPriority) { - case DiscreteEventPriority: - schedulerPriority = ImmediatePriority; - break; +var valueStack = []; +var fiberStack; - case ContinuousEventPriority: - schedulerPriority = UserBlockingPriority; - break; +{ + fiberStack = []; +} - case DefaultEventPriority: - schedulerPriority = NormalPriority$1; - break; +var index = -1; - case IdleEventPriority: - schedulerPriority = IdlePriority; - break; +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} - default: - schedulerPriority = NormalPriority$1; - break; - } +function pop(cursor, fiber) { + if (index < 0) { + { + error("Unexpected pop."); + } - injectedHook.onCommitFiberRoot( - rendererID, - root, - schedulerPriority, - didError - ); - } - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; + return; + } - error("React instrumentation encountered an error: %s", err); - } - } + { + if (fiber !== fiberStack[index]) { + error("Unexpected Fiber popped."); } } -} -function onPostCommitRoot(root) { - if ( - injectedHook && - typeof injectedHook.onPostCommitFiberRoot === "function" - ) { - try { - injectedHook.onPostCommitFiberRoot(rendererID, root); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; - error("React instrumentation encountered an error: %s", err); - } - } - } + cursor.current = valueStack[index]; + valueStack[index] = null; + + { + fiberStack[index] = null; } + + index--; } -function onCommitUnmount(fiber) { - if (injectedHook && typeof injectedHook.onCommitFiberUnmount === "function") { - try { - injectedHook.onCommitFiberUnmount(rendererID, fiber); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; - error("React instrumentation encountered an error: %s", err); - } - } - } +function push(cursor, value, fiber) { + index++; + valueStack[index] = cursor.current; + + { + fiberStack[index] = fiber; } -} -function setIsStrictModeForDevtools(newIsStrictMode) { - { - if (typeof log$2 === "function") { - // We're in a test because Scheduler.log only exists - // in SchedulerMock. To reduce the noise in strict mode tests, - // suppress warnings and disable scheduler yielding during the double render - unstable_setDisableYieldValue(newIsStrictMode); - setSuppressWarning(newIsStrictMode); - } - - if (injectedHook && typeof injectedHook.setStrictMode === "function") { - try { - injectedHook.setStrictMode(rendererID, newIsStrictMode); - } catch (err) { - { - if (!hasLoggedError) { - hasLoggedError = true; - - error("React instrumentation encountered an error: %s", err); - } - } - } - } - } -} // Profiler API hooks - -function injectProfilingHooks(profilingHooks) { - injectedProfilingHooks = profilingHooks; + + cursor.current = value; } -function getLaneLabelMap() { - if (enableSchedulingProfiler) { - var map = new Map(); - var lane = 1; +var emptyContextObject = {}; - for (var index = 0; index < TotalLanes; index++) { - var label = getLabelForLane(lane); - map.set(lane, label); - lane *= 2; - } +{ + Object.freeze(emptyContextObject); +} // A cursor to the current merged context object on the stack. - return map; - } else { - return null; +function hasContextChanged() { + { + return false; } } -function markCommitStarted(lanes) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStarted === "function" - ) { - injectedProfilingHooks.markCommitStarted(lanes); - } - } -} -function markCommitStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markCommitStopped === "function" - ) { - injectedProfilingHooks.markCommitStopped(); - } - } -} -function markComponentRenderStarted(fiber) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStarted === "function" - ) { - injectedProfilingHooks.markComponentRenderStarted(fiber); - } - } -} -function markComponentRenderStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentRenderStopped === "function" - ) { - injectedProfilingHooks.markComponentRenderStopped(); - } - } -} -function markComponentPassiveEffectMountStarted(fiber) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); - } - } -} -function markComponentPassiveEffectMountStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectMountStopped(); - } - } -} -function markComponentPassiveEffectUnmountStarted(fiber) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); - } - } -} -function markComponentPassiveEffectUnmountStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); - } - } -} -function markComponentLayoutEffectMountStarted(fiber) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); - } - } -} -function markComponentLayoutEffectMountStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectMountStopped(); - } - } -} -function markComponentLayoutEffectUnmountStarted(fiber) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); - } - } -} -function markComponentLayoutEffectUnmountStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === - "function" - ) { - injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); - } - } -} -function markComponentErrored(fiber, thrownValue, lanes) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentErrored === "function" - ) { - injectedProfilingHooks.markComponentErrored(fiber, thrownValue, lanes); - } - } -} -function markComponentSuspended(fiber, wakeable, lanes) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markComponentSuspended === "function" - ) { - injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); - } - } -} -function markLayoutEffectsStarted(lanes) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStarted === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStarted(lanes); - } - } -} -function markLayoutEffectsStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markLayoutEffectsStopped === "function" - ) { - injectedProfilingHooks.markLayoutEffectsStopped(); - } - } -} -function markPassiveEffectsStarted(lanes) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStarted === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStarted(lanes); - } - } -} -function markPassiveEffectsStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markPassiveEffectsStopped === "function" - ) { - injectedProfilingHooks.markPassiveEffectsStopped(); - } - } -} -function markRenderStarted(lanes) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStarted === "function" - ) { - injectedProfilingHooks.markRenderStarted(lanes); - } - } -} -function markRenderYielded() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderYielded === "function" - ) { - injectedProfilingHooks.markRenderYielded(); - } - } -} -function markRenderStopped() { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderStopped === "function" - ) { - injectedProfilingHooks.markRenderStopped(); - } +function isContextProvider(type) { + { + return false; } } -function markRenderScheduled(lane) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markRenderScheduled === "function" - ) { - injectedProfilingHooks.markRenderScheduled(lane); - } + +function processChildContext(fiber, type, parentContext) { + { + return parentContext; } } -function markForceUpdateScheduled(fiber, lane) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markForceUpdateScheduled === "function" - ) { - injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); - } + +function findCurrentUnmaskedContext(fiber) { + { + return emptyContextObject; } } -function markStateUpdateScheduled(fiber, lane) { - if (enableSchedulingProfiler) { - if ( - injectedProfilingHooks !== null && - typeof injectedProfilingHooks.markStateUpdateScheduled === "function" - ) { - injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); - } - } + +var LegacyRoot = 0; +var ConcurrentRoot = 1; + +// We use the existence of the state object as an indicator that the component +// is hidden. +var OffscreenVisible = + /* */ + 1; +var OffscreenDetached = + /* */ + 2; +var OffscreenPassiveEffectsConnected = + /* */ + 4; +function isOffscreenManual(offscreenFiber) { + return ( + offscreenFiber.memoizedProps !== null && + offscreenFiber.memoizedProps.mode === "manual" + ); } var NoMode = @@ -6380,7 +5853,7 @@ var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros. // Based on: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 -var log$1 = Math.log; +var log$2 = Math.log; var LN2 = Math.LN2; function clz32Fallback(x) { @@ -6390,7 +5863,7 @@ function clz32Fallback(x) { return 32; } - return (31 - ((log$1(asUint) / LN2) | 0)) | 0; + return (31 - ((log$2(asUint) / LN2) | 0)) | 0; } // If those values are changed that package should be rebuilt and redeployed. @@ -7327,7 +6800,7 @@ var ContinuousEventPriority = InputContinuousLane; var DefaultEventPriority = DefaultLane; var IdleEventPriority = IdleLane; var currentUpdatePriority = NoLane; -function getCurrentUpdatePriority$1() { +function getCurrentUpdatePriority() { return currentUpdatePriority; } function setCurrentUpdatePriority(newPriority) { @@ -7370,35426 +6843,35899 @@ function lanesToEventPriority(lanes) { return IdleEventPriority; } -// This is imported by the event replaying implementation in React DOM. It's -// in a separate file to break a circular dependency between the renderer and -// the reconciler. -function isRootDehydrated(root) { - var currentState = root.current.memoizedState; - return currentState.isDehydrated; -} +// This module only exists as an ESM wrapper around the external CommonJS +var scheduleCallback$2 = Scheduler.unstable_scheduleCallback; +var cancelCallback$1 = Scheduler.unstable_cancelCallback; +var shouldYield = Scheduler.unstable_shouldYield; +var requestPaint = Scheduler.unstable_requestPaint; +var now$1 = Scheduler.unstable_now; +var getCurrentPriorityLevel = Scheduler.unstable_getCurrentPriorityLevel; +var ImmediatePriority = Scheduler.unstable_ImmediatePriority; +var UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; +var NormalPriority$1 = Scheduler.unstable_NormalPriority; +var LowPriority = Scheduler.unstable_LowPriority; +var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* +// on scheduler/unstable_mock, which we'll need for internal testing -var _attemptSynchronousHydration; +var log$1 = Scheduler.log; +var unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue; -function setAttemptSynchronousHydration(fn) { - _attemptSynchronousHydration = fn; -} -function attemptSynchronousHydration$1(fiber) { - _attemptSynchronousHydration(fiber); -} -var attemptDiscreteHydration$1; -function setAttemptDiscreteHydration(fn) { - attemptDiscreteHydration$1 = fn; -} -var attemptContinuousHydration$1; -function setAttemptContinuousHydration(fn) { - attemptContinuousHydration$1 = fn; -} -var attemptHydrationAtCurrentPriority$1; -function setAttemptHydrationAtCurrentPriority(fn) { - attemptHydrationAtCurrentPriority$1 = fn; -} -var getCurrentUpdatePriority; -function setGetCurrentUpdatePriority(fn) { - getCurrentUpdatePriority = fn; -} -var attemptHydrationAtPriority; -function setAttemptHydrationAtPriority(fn) { - attemptHydrationAtPriority = fn; -} // TODO: Upgrade this definition once we're on a newer version of Flow that -// has this definition built-in. +var rendererID = null; +var injectedHook = null; +var injectedProfilingHooks = null; +var hasLoggedError = false; +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; + } -var hasScheduledReplayAttempt = false; // The queue of discrete events to be replayed. + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; -var queuedDiscreteEvents = []; // Indicates if any continuous event targets are non-null for early bailout. -// if the last target was dehydrated. + 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; + } -var queuedFocus = null; -var queuedDrag = null; -var queuedMouse = null; // For pointer events there can be one latest event per pointerId. + if (!hook.supportsFiber) { + { + error( + "The installed version of React DevTools is too old and will not work " + + "with the current version of React. Please update React DevTools. " + + "https://reactjs.org/link/react-devtools" + ); + } // DevTools exists, even though it doesn't support Fiber. -var queuedPointers = new Map(); -var queuedPointerCaptures = new Map(); // We could consider replaying selectionchange and touchmoves too. + return true; + } -var queuedExplicitHydrationTargets = []; -function hasQueuedDiscreteEvents() { - return queuedDiscreteEvents.length > 0; -} -var discreteReplayableEvents = [ - "mousedown", - "mouseup", - "touchcancel", - "touchend", - "touchstart", - "auxclick", - "dblclick", - "pointercancel", - "pointerdown", - "pointerup", - "dragend", - "dragstart", - "drop", - "compositionend", - "compositionstart", - "keydown", - "keypress", - "keyup", - "input", - "textInput", // Intentionally camelCase - "copy", - "cut", - "paste", - "click", - "change", - "contextmenu", - "reset", - "submit" -]; -function isDiscreteEventThatRequiresHydration(eventType) { - return discreteReplayableEvents.indexOf(eventType) > -1; -} + try { + if (enableSchedulingProfiler) { + // Conditionally inject these hooks only if Timeline profiler is supported by this build. + // This gives DevTools a way to feature detect that isn't tied to version number + // (since profiling and timeline are controlled by different feature flags). + internals = assign({}, internals, { + getLaneLabelMap: getLaneLabelMap, + injectProfilingHooks: injectProfilingHooks + }); + } -function createQueuedReplayableEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - return { - blockedOn: blockedOn, - domEventName: domEventName, - eventSystemFlags: eventSystemFlags, - nativeEvent: nativeEvent, - targetContainers: [targetContainer] - }; -} + rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks. -function queueDiscreteEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - return; + injectedHook = hook; + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + { + error("React instrumentation encountered an error: %s.", err); + } } - var queuedEvent = createQueuedReplayableEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - queuedDiscreteEvents.push(queuedEvent); - - if (queuedDiscreteEvents.length === 1) { - // If this was the first discrete event, we might be able to - // synchronously unblock it so that preventDefault still works. - while (queuedEvent.blockedOn !== null) { - var fiber = getInstanceFromNode$1(queuedEvent.blockedOn); + if (hook.checkDCE) { + // This is the real DevTools. + return true; + } else { + // This is likely a hook installed by Fast Refresh runtime. + return false; + } +} +function onScheduleRoot(root, children) { + { + if ( + injectedHook && + typeof injectedHook.onScheduleFiberRoot === "function" + ) { + try { + injectedHook.onScheduleFiberRoot(rendererID, root, children); + } catch (err) { + if (!hasLoggedError) { + hasLoggedError = true; - if (fiber === null) { - break; + error("React instrumentation encountered an error: %s", err); + } } + } + } +} +function onCommitRoot$1(root, eventPriority) { + if (injectedHook && typeof injectedHook.onCommitFiberRoot === "function") { + try { + var didError = (root.current.flags & DidCapture) === DidCapture; - attemptSynchronousHydration$1(fiber); + if (enableProfilerTimer) { + var schedulerPriority; - if (queuedEvent.blockedOn === null) { - // We got unblocked by hydration. Let's try again. - replayUnblockedEvents(); // If we're reblocked, on an inner boundary, we might need - // to attempt hydrating that one. + switch (eventPriority) { + case DiscreteEventPriority: + schedulerPriority = ImmediatePriority; + break; - continue; - } else { - // We're still blocked from hydration, we have to give up - // and replay later. - break; - } - } - } -} // Resets the replaying for this type of continuous event to no event. + case ContinuousEventPriority: + schedulerPriority = UserBlockingPriority; + break; -function clearIfContinuousEvent(domEventName, nativeEvent) { - switch (domEventName) { - case "focusin": - case "focusout": - queuedFocus = null; - break; + case DefaultEventPriority: + schedulerPriority = NormalPriority$1; + break; - case "dragenter": - case "dragleave": - queuedDrag = null; - break; + case IdleEventPriority: + schedulerPriority = IdlePriority; + break; - case "mouseover": - case "mouseout": - queuedMouse = null; - break; + default: + schedulerPriority = NormalPriority$1; + break; + } - case "pointerover": - case "pointerout": { - var pointerId = nativeEvent.pointerId; - queuedPointers.delete(pointerId); - break; - } + injectedHook.onCommitFiberRoot( + rendererID, + root, + schedulerPriority, + didError + ); + } + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; - case "gotpointercapture": - case "lostpointercapture": { - var _pointerId = nativeEvent.pointerId; - queuedPointerCaptures.delete(_pointerId); - break; + error("React instrumentation encountered an error: %s", err); + } + } } } } - -function accumulateOrCreateContinuousQueuedReplayableEvent( - existingQueuedEvent, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { +function onPostCommitRoot(root) { if ( - existingQueuedEvent === null || - existingQueuedEvent.nativeEvent !== nativeEvent + injectedHook && + typeof injectedHook.onPostCommitFiberRoot === "function" ) { - var queuedEvent = createQueuedReplayableEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - - if (blockedOn !== null) { - var fiber = getInstanceFromNode$1(blockedOn); + try { + injectedHook.onPostCommitFiberRoot(rendererID, root); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; - if (fiber !== null) { - // Attempt to increase the priority of this target. - attemptContinuousHydration$1(fiber); + error("React instrumentation encountered an error: %s", err); + } } } - - return queuedEvent; - } // If we have already queued this exact event, then it's because - // the different event systems have different DOM event listeners. - // We can accumulate the flags, and the targetContainers, and - // store a single event to be replayed. - - existingQueuedEvent.eventSystemFlags |= eventSystemFlags; - var targetContainers = existingQueuedEvent.targetContainers; - - if ( - targetContainer !== null && - targetContainers.indexOf(targetContainer) === -1 - ) { - targetContainers.push(targetContainer); } - - return existingQueuedEvent; } +function onCommitUnmount(fiber) { + if (injectedHook && typeof injectedHook.onCommitFiberUnmount === "function") { + try { + injectedHook.onCommitFiberUnmount(rendererID, fiber); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; -function queueIfContinuousEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - // These set relatedTarget to null because the replayed event will be treated as if we - // moved from outside the window (no target) onto the target once it hydrates. - // Instead of mutating we could clone the event. - switch (domEventName) { - case "focusin": { - var focusEvent = nativeEvent; - queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent( - queuedFocus, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - focusEvent - ); - return true; - } - - case "dragenter": { - var dragEvent = nativeEvent; - queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent( - queuedDrag, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - dragEvent - ); - return true; + error("React instrumentation encountered an error: %s", err); + } + } } - - case "mouseover": { - var mouseEvent = nativeEvent; - queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent( - queuedMouse, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - mouseEvent - ); - return true; + } +} +function setIsStrictModeForDevtools(newIsStrictMode) { + { + if (typeof log$1 === "function") { + // We're in a test because Scheduler.log only exists + // in SchedulerMock. To reduce the noise in strict mode tests, + // suppress warnings and disable scheduler yielding during the double render + unstable_setDisableYieldValue(newIsStrictMode); + setSuppressWarning(newIsStrictMode); } - case "pointerover": { - var pointerEvent = nativeEvent; - var pointerId = pointerEvent.pointerId; - queuedPointers.set( - pointerId, - accumulateOrCreateContinuousQueuedReplayableEvent( - queuedPointers.get(pointerId) || null, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - pointerEvent - ) - ); - return true; - } + if (injectedHook && typeof injectedHook.setStrictMode === "function") { + try { + injectedHook.setStrictMode(rendererID, newIsStrictMode); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; - case "gotpointercapture": { - var _pointerEvent = nativeEvent; - var _pointerId2 = _pointerEvent.pointerId; - queuedPointerCaptures.set( - _pointerId2, - accumulateOrCreateContinuousQueuedReplayableEvent( - queuedPointerCaptures.get(_pointerId2) || null, - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - _pointerEvent - ) - ); - return true; + error("React instrumentation encountered an error: %s", err); + } + } + } } } +} // Profiler API hooks - return false; -} // Check if this target is unblocked. Returns true if it's unblocked. - -function attemptExplicitHydrationTarget(queuedTarget) { - // TODO: This function shares a lot of logic with findInstanceBlockingEvent. - // Try to unify them. It's a bit tricky since it would require two return - // values. - var targetInst = getClosestInstanceFromNode(queuedTarget.target); - - if (targetInst !== null) { - var nearestMounted = getNearestMountedFiber(targetInst); - - if (nearestMounted !== null) { - var tag = nearestMounted.tag; - - if (tag === SuspenseComponent) { - var instance = getSuspenseInstanceFromFiber(nearestMounted); - - if (instance !== null) { - // We're blocked on hydrating this boundary. - // Increase its priority. - queuedTarget.blockedOn = instance; - attemptHydrationAtPriority(queuedTarget.priority, function () { - attemptHydrationAtCurrentPriority$1(nearestMounted); - }); - return; - } - } else if (tag === HostRoot) { - var root = nearestMounted.stateNode; +function injectProfilingHooks(profilingHooks) { + injectedProfilingHooks = profilingHooks; +} - if (isRootDehydrated(root)) { - queuedTarget.blockedOn = getContainerFromFiber(nearestMounted); // We don't currently have a way to increase the priority of - // a root other than sync. +function getLaneLabelMap() { + if (enableSchedulingProfiler) { + var map = new Map(); + var lane = 1; - return; - } - } + for (var index = 0; index < TotalLanes; index++) { + var label = getLabelForLane(lane); + map.set(lane, label); + lane *= 2; } - } - queuedTarget.blockedOn = null; + return map; + } else { + return null; + } } -function queueExplicitHydrationTarget(target) { - // TODO: This will read the priority if it's dispatched by the React - // event system but not native events. Should read window.event.type, like - // we do for updates (getCurrentEventPriority). - var updatePriority = getCurrentUpdatePriority(); - var queuedTarget = { - blockedOn: null, - target: target, - priority: updatePriority - }; - var i = 0; - - for (; i < queuedExplicitHydrationTargets.length; i++) { - // Stop once we hit the first target with lower priority than +function markCommitStarted(lanes) { + if (enableSchedulingProfiler) { if ( - !isHigherEventPriority( - updatePriority, - queuedExplicitHydrationTargets[i].priority - ) + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markCommitStarted === "function" ) { - break; + injectedProfilingHooks.markCommitStarted(lanes); } } - - queuedExplicitHydrationTargets.splice(i, 0, queuedTarget); - - if (i === 0) { - attemptExplicitHydrationTarget(queuedTarget); - } } - -function attemptReplayContinuousQueuedEvent(queuedEvent) { - if (queuedEvent.blockedOn !== null) { - return false; +function markCommitStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markCommitStopped === "function" + ) { + injectedProfilingHooks.markCommitStopped(); + } } +} +function markComponentRenderStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentRenderStarted === "function" + ) { + injectedProfilingHooks.markComponentRenderStarted(fiber); + } + } +} +function markComponentRenderStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentRenderStopped === "function" + ) { + injectedProfilingHooks.markComponentRenderStopped(); + } + } +} +function markComponentPassiveEffectMountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); + } + } +} +function markComponentPassiveEffectMountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectMountStopped(); + } + } +} +function markComponentPassiveEffectUnmountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); + } + } +} +function markComponentPassiveEffectUnmountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); + } + } +} +function markComponentLayoutEffectMountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); + } + } +} +function markComponentLayoutEffectMountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectMountStopped(); + } + } +} +function markComponentLayoutEffectUnmountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); + } + } +} +function markComponentLayoutEffectUnmountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); + } + } +} +function markComponentErrored(fiber, thrownValue, lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentErrored === "function" + ) { + injectedProfilingHooks.markComponentErrored(fiber, thrownValue, lanes); + } + } +} +function markComponentSuspended(fiber, wakeable, lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentSuspended === "function" + ) { + injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); + } + } +} +function markLayoutEffectsStarted(lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markLayoutEffectsStarted === "function" + ) { + injectedProfilingHooks.markLayoutEffectsStarted(lanes); + } + } +} +function markLayoutEffectsStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markLayoutEffectsStopped === "function" + ) { + injectedProfilingHooks.markLayoutEffectsStopped(); + } + } +} +function markPassiveEffectsStarted(lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markPassiveEffectsStarted === "function" + ) { + injectedProfilingHooks.markPassiveEffectsStarted(lanes); + } + } +} +function markPassiveEffectsStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markPassiveEffectsStopped === "function" + ) { + injectedProfilingHooks.markPassiveEffectsStopped(); + } + } +} +function markRenderStarted(lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderStarted === "function" + ) { + injectedProfilingHooks.markRenderStarted(lanes); + } + } +} +function markRenderYielded() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderYielded === "function" + ) { + injectedProfilingHooks.markRenderYielded(); + } + } +} +function markRenderStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderStopped === "function" + ) { + injectedProfilingHooks.markRenderStopped(); + } + } +} +function markRenderScheduled(lane) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderScheduled === "function" + ) { + injectedProfilingHooks.markRenderScheduled(lane); + } + } +} +function markForceUpdateScheduled(fiber, lane) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markForceUpdateScheduled === "function" + ) { + injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); + } + } +} +function markStateUpdateScheduled(fiber, lane) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markStateUpdateScheduled === "function" + ) { + injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); + } + } +} - var targetContainers = queuedEvent.targetContainers; - - while (targetContainers.length > 0) { - var targetContainer = targetContainers[0]; - var nextBlockedOn = findInstanceBlockingEvent( - queuedEvent.domEventName, - queuedEvent.eventSystemFlags, - targetContainer, - queuedEvent.nativeEvent - ); - - if (nextBlockedOn === null) { - if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - var nativeEvent = queuedEvent.nativeEvent; - var nativeEventClone = new nativeEvent.constructor( - nativeEvent.type, - nativeEvent - ); - setReplayingEvent(nativeEventClone); - nativeEvent.target.dispatchEvent(nativeEventClone); - resetReplayingEvent(); - } else { - setReplayingEvent(queuedEvent.nativeEvent); - dispatchEventForPluginEventSystem( - queuedEvent.domEventName, - queuedEvent.eventSystemFlags, - queuedEvent.nativeEvent, - return_targetInst, - targetContainer - ); - resetReplayingEvent(); - } - } else { - // We're still blocked. Try again later. - var fiber = getInstanceFromNode$1(nextBlockedOn); - - if (fiber !== null) { - attemptContinuousHydration$1(fiber); - } +/** + * 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 + ); +} - queuedEvent.blockedOn = nextBlockedOn; - return false; - } // This target container was successfully dispatched. Try the next. +var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] - targetContainers.shift(); +var syncQueue = null; +var includesLegacySyncCallbacks = false; +var isFlushingSyncQueue = false; +function scheduleSyncCallback(callback) { + // Push this callback into an internal queue. We'll flush these either in + // the next tick, or earlier if something calls `flushSyncCallbackQueue`. + if (syncQueue === null) { + syncQueue = [callback]; + } else { + // Push onto existing queue. Don't need to schedule a callback because + // we already scheduled one when we created the queue. + syncQueue.push(callback); } - - return true; } - -function attemptReplayContinuousQueuedEventInMap(queuedEvent, key, map) { - if (attemptReplayContinuousQueuedEvent(queuedEvent)) { - map.delete(key); +function scheduleLegacySyncCallback(callback) { + includesLegacySyncCallbacks = true; + scheduleSyncCallback(callback); +} +function flushSyncCallbacksOnlyInLegacyMode() { + // Only flushes the queue if there's a legacy sync callback scheduled. + // TODO: There's only a single type of callback: performSyncOnWorkOnRoot. So + // it might make more sense for the queue to be a list of roots instead of a + // list of generic callbacks. Then we can have two: one for legacy roots, one + // for concurrent roots. And this method would only flush the legacy ones. + if (includesLegacySyncCallbacks) { + flushSyncCallbacks(); } } +function flushSyncCallbacks() { + if (!isFlushingSyncQueue && syncQueue !== null) { + // Prevent re-entrance. + isFlushingSyncQueue = true; // Set the event priority to discrete + // TODO: Is this necessary anymore? The only user code that runs in this + // queue is in the render or commit phases, which already set the + // event priority. Should be able to remove. -function replayUnblockedEvents() { - hasScheduledReplayAttempt = false; + var previousUpdatePriority = getCurrentUpdatePriority(); + setCurrentUpdatePriority(DiscreteEventPriority); + var errors = null; + var queue = syncQueue; // $FlowFixMe[incompatible-use] found when upgrading Flow - if (!enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - // First replay discrete events. - while (queuedDiscreteEvents.length > 0) { - var nextDiscreteEvent = queuedDiscreteEvents[0]; + for (var i = 0; i < queue.length; i++) { + // $FlowFixMe[incompatible-use] found when upgrading Flow + var callback = queue[i]; - if (nextDiscreteEvent.blockedOn !== null) { - // We're still blocked. - // Increase the priority of this boundary to unblock - // the next discrete event. - var fiber = getInstanceFromNode$1(nextDiscreteEvent.blockedOn); + try { + do { + var isSync = true; // $FlowFixMe[incompatible-type] we bail out when we get a null - if (fiber !== null) { - attemptDiscreteHydration$1(fiber); + callback = callback(isSync); + } while (callback !== null); + } catch (error) { + // Collect errors so we can rethrow them at the end + if (errors === null) { + errors = [error]; + } else { + errors.push(error); } - - break; } + } - var targetContainers = nextDiscreteEvent.targetContainers; - - while (targetContainers.length > 0) { - var targetContainer = targetContainers[0]; - var nextBlockedOn = findInstanceBlockingEvent( - nextDiscreteEvent.domEventName, - nextDiscreteEvent.eventSystemFlags, - targetContainer, - nextDiscreteEvent.nativeEvent - ); + syncQueue = null; + includesLegacySyncCallbacks = false; + setCurrentUpdatePriority(previousUpdatePriority); + isFlushingSyncQueue = false; - if (nextBlockedOn === null) { - // This whole function is in !enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay, - // so we don't need the new replay behavior code branch. - setReplayingEvent(nextDiscreteEvent.nativeEvent); - dispatchEventForPluginEventSystem( - nextDiscreteEvent.domEventName, - nextDiscreteEvent.eventSystemFlags, - nextDiscreteEvent.nativeEvent, - return_targetInst, - targetContainer - ); - resetReplayingEvent(); + if (errors !== null) { + if (errors.length > 1) { + if (typeof AggregateError === "function") { + // eslint-disable-next-line no-undef + throw new AggregateError(errors); } else { - // We're still blocked. Try again later. - nextDiscreteEvent.blockedOn = nextBlockedOn; - break; - } // This target container was successfully dispatched. Try the next. - - targetContainers.shift(); - } + for (var _i = 1; _i < errors.length; _i++) { + scheduleCallback$2( + ImmediatePriority, + throwError.bind(null, errors[_i]) + ); + } - if (nextDiscreteEvent.blockedOn === null) { - // We've successfully replayed the first event. Let's try the next one. - queuedDiscreteEvents.shift(); + var firstError = errors[0]; + throw firstError; + } + } else { + var error = errors[0]; + throw error; } } - } // Next replay any continuous events. - - if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) { - queuedFocus = null; - } - - if (queuedDrag !== null && attemptReplayContinuousQueuedEvent(queuedDrag)) { - queuedDrag = null; } - if (queuedMouse !== null && attemptReplayContinuousQueuedEvent(queuedMouse)) { - queuedMouse = null; - } - - queuedPointers.forEach(attemptReplayContinuousQueuedEventInMap); - queuedPointerCaptures.forEach(attemptReplayContinuousQueuedEventInMap); + return null; } -function scheduleCallbackIfUnblocked(queuedEvent, unblocked) { - if (queuedEvent.blockedOn === unblocked) { - queuedEvent.blockedOn = null; +function throwError(error) { + throw error; +} - if (!hasScheduledReplayAttempt) { - hasScheduledReplayAttempt = true; // Schedule a callback to attempt replaying as many events as are - // now unblocked. This first might not actually be unblocked yet. - // We could check it early to avoid scheduling an unnecessary callback. +var nativeConsole = console; +var nativeConsoleLog = null; +var pendingGroupArgs = []; +var printedGroupIndex = -1; - Scheduler.unstable_scheduleCallback( - Scheduler.unstable_NormalPriority, - replayUnblockedEvents - ); - } - } +function formatLanes(laneOrLanes) { + return "0b" + laneOrLanes.toString(2).padStart(31, "0"); } -function retryIfBlockedOn(unblocked) { - // Mark anything that was blocked on this as no longer blocked - // and eligible for a replay. - if (queuedDiscreteEvents.length > 0) { - scheduleCallbackIfUnblocked(queuedDiscreteEvents[0], unblocked); // This is a exponential search for each boundary that commits. I think it's - // worth it because we expect very few discrete events to queue up and once - // we are actually fully unblocked it will be fast to replay them. +function group() { + for ( + var _len = arguments.length, groupArgs = new Array(_len), _key = 0; + _key < _len; + _key++ + ) { + groupArgs[_key] = arguments[_key]; + } - for (var i = 1; i < queuedDiscreteEvents.length; i++) { - var queuedEvent = queuedDiscreteEvents[i]; + pendingGroupArgs.push(groupArgs); - if (queuedEvent.blockedOn === unblocked) { - queuedEvent.blockedOn = null; - } - } + if (nativeConsoleLog === null) { + nativeConsoleLog = nativeConsole.log; + nativeConsole.log = log; } +} - if (queuedFocus !== null) { - scheduleCallbackIfUnblocked(queuedFocus, unblocked); - } +function groupEnd() { + pendingGroupArgs.pop(); - if (queuedDrag !== null) { - scheduleCallbackIfUnblocked(queuedDrag, unblocked); + while (printedGroupIndex >= pendingGroupArgs.length) { + nativeConsole.groupEnd(); + printedGroupIndex--; } - if (queuedMouse !== null) { - scheduleCallbackIfUnblocked(queuedMouse, unblocked); + if (pendingGroupArgs.length === 0) { + nativeConsole.log = nativeConsoleLog; + nativeConsoleLog = null; } +} - var unblock = function (queuedEvent) { - return scheduleCallbackIfUnblocked(queuedEvent, unblocked); - }; - - queuedPointers.forEach(unblock); - queuedPointerCaptures.forEach(unblock); - - for (var _i = 0; _i < queuedExplicitHydrationTargets.length; _i++) { - var queuedTarget = queuedExplicitHydrationTargets[_i]; - - if (queuedTarget.blockedOn === unblocked) { - queuedTarget.blockedOn = null; +function log() { + if (printedGroupIndex < pendingGroupArgs.length - 1) { + for (var i = printedGroupIndex + 1; i < pendingGroupArgs.length; i++) { + var groupArgs = pendingGroupArgs[i]; + nativeConsole.group.apply(nativeConsole, groupArgs); } - } - while (queuedExplicitHydrationTargets.length > 0) { - var nextExplicitTarget = queuedExplicitHydrationTargets[0]; + printedGroupIndex = pendingGroupArgs.length - 1; + } - if (nextExplicitTarget.blockedOn !== null) { - // We're still blocked. - break; - } else { - attemptExplicitHydrationTarget(nextExplicitTarget); + if (typeof nativeConsoleLog === "function") { + nativeConsoleLog.apply(void 0, arguments); + } else { + nativeConsole.log.apply(nativeConsole, arguments); + } +} - if (nextExplicitTarget.blockedOn === null) { - // We're unblocked. - queuedExplicitHydrationTargets.shift(); - } +var REACT_LOGO_STYLE = + "background-color: #20232a; color: #61dafb; padding: 0 2px;"; +function logCommitStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c commit%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" + ); } } } - -var ReactCurrentBatchConfig$3 = ReactSharedInternals.ReactCurrentBatchConfig; // TODO: can we stop exporting these? - -var _enabled = true; // This is exported in FB builds for use by legacy FB layer infra. -// We'd like to remove this but it's not clear if this is safe. - -function setEnabled(enabled) { - _enabled = !!enabled; -} -function isEnabled() { - return _enabled; +function logCommitStopped() { + { + if (enableDebugTracing) { + groupEnd(); + } + } } -function createEventListenerWrapperWithPriority( - targetContainer, - domEventName, - eventSystemFlags -) { - var eventPriority = getEventPriority(domEventName); - var listenerWrapper; - - switch (eventPriority) { - case DiscreteEventPriority: - listenerWrapper = dispatchDiscreteEvent; - break; +var PossiblyWeakMap$1 = typeof WeakMap === "function" ? WeakMap : Map; // $FlowFixMe: Flow cannot handle polymorphic WeakMaps - case ContinuousEventPriority: - listenerWrapper = dispatchContinuousEvent; - break; +var wakeableIDs = new PossiblyWeakMap$1(); +var wakeableID = 0; - case DefaultEventPriority: - default: - listenerWrapper = dispatchEvent; - break; +function getWakeableID(wakeable) { + if (!wakeableIDs.has(wakeable)) { + wakeableIDs.set(wakeable, wakeableID++); } - return listenerWrapper.bind( - null, - domEventName, - eventSystemFlags, - targetContainer - ); + return wakeableIDs.get(wakeable); } -function dispatchDiscreteEvent( - domEventName, - eventSystemFlags, - container, - nativeEvent -) { - var previousPriority = getCurrentUpdatePriority$1(); - var prevTransition = ReactCurrentBatchConfig$3.transition; - ReactCurrentBatchConfig$3.transition = null; - - try { - setCurrentUpdatePriority(DiscreteEventPriority); - dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig$3.transition = prevTransition; +function logComponentSuspended(componentName, wakeable) { + { + if (enableDebugTracing) { + var id = getWakeableID(wakeable); + var display = wakeable.displayName || wakeable; + log( + "%c\u269B\uFE0F%c " + componentName + " suspended", + REACT_LOGO_STYLE, + "color: #80366d; font-weight: bold;", + id, + display + ); + wakeable.then( + function () { + log( + "%c\u269B\uFE0F%c " + componentName + " resolved", + REACT_LOGO_STYLE, + "color: #80366d; font-weight: bold;", + id, + display + ); + }, + function () { + log( + "%c\u269B\uFE0F%c " + componentName + " rejected", + REACT_LOGO_STYLE, + "color: #80366d; font-weight: bold;", + id, + display + ); + } + ); + } } } - -function dispatchContinuousEvent( - domEventName, - eventSystemFlags, - container, - nativeEvent -) { - var previousPriority = getCurrentUpdatePriority$1(); - var prevTransition = ReactCurrentBatchConfig$3.transition; - ReactCurrentBatchConfig$3.transition = null; - - try { - setCurrentUpdatePriority(ContinuousEventPriority); - dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent); - } finally { - setCurrentUpdatePriority(previousPriority); - ReactCurrentBatchConfig$3.transition = prevTransition; +function logLayoutEffectsStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c layout effects%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" + ); + } } } - -function dispatchEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - if (!_enabled) { - return; +function logLayoutEffectsStopped() { + { + if (enableDebugTracing) { + groupEnd(); + } } - - if (enableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay) { - dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - } else { - dispatchEventOriginal( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); +} +function logPassiveEffectsStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c passive effects%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" + ); + } } } - -function dispatchEventOriginal( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - // TODO: replaying capture phase events is currently broken - // because we used to do it during top-level native bubble handlers - // but now we use different bubble and capture handlers. - // In eager mode, we attach capture listeners early, so we need - // to filter them out until we fix the logic to handle them correctly. - var allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0; - - if ( - allowReplay && - hasQueuedDiscreteEvents() && - isDiscreteEventThatRequiresHydration(domEventName) - ) { - // If we already have a queue of discrete events, and this is another discrete - // event, then we can't dispatch it regardless of its target, since they - // need to dispatch in order. - queueDiscreteEvent( - null, // Flags that we're not actually blocked on anything as far as we know. - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - return; +function logPassiveEffectsStopped() { + { + if (enableDebugTracing) { + groupEnd(); + } } - - var blockedOn = findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - - if (blockedOn === null) { - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - return_targetInst, - targetContainer - ); - - if (allowReplay) { - clearIfContinuousEvent(domEventName, nativeEvent); +} +function logRenderStarted(lanes) { + { + if (enableDebugTracing) { + group( + "%c\u269B\uFE0F%c render%c (" + formatLanes(lanes) + ")", + REACT_LOGO_STYLE, + "", + "font-weight: normal;" + ); } - - return; } - - if (allowReplay) { - if (isDiscreteEventThatRequiresHydration(domEventName)) { - // This to be replayed later once the target is available. - queueDiscreteEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent +} +function logRenderStopped() { + { + if (enableDebugTracing) { + groupEnd(); + } + } +} +function logForceUpdateScheduled(componentName, lane) { + { + if (enableDebugTracing) { + log( + "%c\u269B\uFE0F%c " + + componentName + + " forced update %c(" + + formatLanes(lane) + + ")", + REACT_LOGO_STYLE, + "color: #db2e1f; font-weight: bold;", + "" + ); + } + } +} +function logStateUpdateScheduled(componentName, lane, payloadOrAction) { + { + if (enableDebugTracing) { + log( + "%c\u269B\uFE0F%c " + + componentName + + " updated state %c(" + + formatLanes(lane) + + ")", + REACT_LOGO_STYLE, + "color: #01a252; font-weight: bold;", + "", + payloadOrAction ); - return; } + } +} - if ( - queueIfContinuousEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ) - ) { - return; - } // We need to clear only if we didn't queue because - // queueing is accumulative. +// This is imported by the event replaying implementation in React DOM. It's +// in a separate file to break a circular dependency between the renderer and +// the reconciler. +function isRootDehydrated(root) { + var currentState = root.current.memoizedState; + return currentState.isDehydrated; +} - clearIfContinuousEvent(domEventName, nativeEvent); - } // This is not replayable so we'll invoke it but without a target, - // in case the event system needs to trace it. +// Intentionally not using it yet to derisk the initial implementation, because +// the way we push/pop these values is a bit unusual. If there's a mistake, I'd +// rather the ids be wrong than crash the whole reconciler. - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - null, - targetContainer - ); +var forkStack = []; +var forkStackIndex = 0; +var treeForkProvider = null; +var treeForkCount = 0; +var idStack = []; +var idStackIndex = 0; +var treeContextProvider = null; +var treeContextId = 1; +var treeContextOverflow = ""; +function isForkedChild(workInProgress) { + warnIfNotHydrating(); + return (workInProgress.flags & Forked) !== NoFlags$1; } +function getForksAtLevel(workInProgress) { + warnIfNotHydrating(); + return treeForkCount; +} +function getTreeId() { + var overflow = treeContextOverflow; + var idWithLeadingBit = treeContextId; + var id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit); + return id.toString(32) + overflow; +} +function pushTreeFork(workInProgress, totalChildren) { + // This is called right after we reconcile an array (or iterator) of child + // fibers, because that's the only place where we know how many children in + // the whole set without doing extra work later, or storing addtional + // information on the fiber. + // + // That's why this function is separate from pushTreeId — it's called during + // the render phase of the fork parent, not the child, which is where we push + // the other context values. + // + // In the Fizz implementation this is much simpler because the child is + // rendered in the same callstack as the parent. + // + // It might be better to just add a `forks` field to the Fiber type. It would + // make this module simpler. + warnIfNotHydrating(); + forkStack[forkStackIndex++] = treeForkCount; + forkStack[forkStackIndex++] = treeForkProvider; + treeForkProvider = workInProgress; + treeForkCount = totalChildren; +} +function pushTreeId(workInProgress, totalChildren, index) { + warnIfNotHydrating(); + idStack[idStackIndex++] = treeContextId; + idStack[idStackIndex++] = treeContextOverflow; + idStack[idStackIndex++] = treeContextProvider; + treeContextProvider = workInProgress; + var baseIdWithLeadingBit = treeContextId; + var baseOverflow = treeContextOverflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part + // of the id; we use it to account for leading 0s. -function dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - var blockedOn = findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); - - if (blockedOn === null) { - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - return_targetInst, - targetContainer - ); - clearIfContinuousEvent(domEventName, nativeEvent); - return; - } + var baseLength = getBitLength(baseIdWithLeadingBit) - 1; + var baseId = baseIdWithLeadingBit & ~(1 << baseLength); + var slot = index + 1; + var length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into + // consideration the leading 1 we use to mark the end of the sequence. - if ( - queueIfContinuousEvent( - blockedOn, - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ) - ) { - nativeEvent.stopPropagation(); - return; - } // We need to clear only if we didn't queue because - // queueing is accumulative. + if (length > 30) { + // We overflowed the bitwise-safe range. Fall back to slower algorithm. + // This branch assumes the length of the base id is greater than 5; it won't + // work for smaller ids, because you need 5 bits per character. + // + // We encode the id in multiple steps: first the base id, then the + // remaining digits. + // + // Each 5 bit sequence corresponds to a single base 32 character. So for + // example, if the current id is 23 bits long, we can convert 20 of those + // bits into a string of 4 characters, with 3 bits left over. + // + // First calculate how many bits in the base id represent a complete + // sequence of characters. + var numberOfOverflowBits = baseLength - (baseLength % 5); // Then create a bitmask that selects only those bits. - clearIfContinuousEvent(domEventName, nativeEvent); + var newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string. - if ( - eventSystemFlags & IS_CAPTURE_PHASE && - isDiscreteEventThatRequiresHydration(domEventName) - ) { - while (blockedOn !== null) { - var fiber = getInstanceFromNode$1(blockedOn); + var newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id. - if (fiber !== null) { - attemptSynchronousHydration$1(fiber); - } + var restOfBaseId = baseId >> numberOfOverflowBits; + var restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because + // we made more room, this time it won't overflow. - var nextBlockedOn = findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent - ); + var restOfLength = getBitLength(totalChildren) + restOfBaseLength; + var restOfNewBits = slot << restOfBaseLength; + var id = restOfNewBits | restOfBaseId; + var overflow = newOverflow + baseOverflow; + treeContextId = (1 << restOfLength) | id; + treeContextOverflow = overflow; + } else { + // Normal path + var newBits = slot << baseLength; - if (nextBlockedOn === null) { - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - return_targetInst, - targetContainer - ); - } + var _id = newBits | baseId; - if (nextBlockedOn === blockedOn) { - break; - } + var _overflow = baseOverflow; + treeContextId = (1 << length) | _id; + treeContextOverflow = _overflow; + } +} +function pushMaterializedTreeId(workInProgress) { + warnIfNotHydrating(); // This component materialized an id. This will affect any ids that appear + // in its children. - blockedOn = nextBlockedOn; - } + var returnFiber = workInProgress.return; - if (blockedOn !== null) { - nativeEvent.stopPropagation(); - } + if (returnFiber !== null) { + var numberOfForks = 1; + var slotIndex = 0; + pushTreeFork(workInProgress, numberOfForks); + pushTreeId(workInProgress, numberOfForks, slotIndex); + } +} - return; - } // This is not replayable so we'll invoke it but without a target, - // in case the event system needs to trace it. +function getBitLength(number) { + return 32 - clz32(number); +} - dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - null, - targetContainer - ); +function getLeadingBit(id) { + return 1 << (getBitLength(id) - 1); } -var return_targetInst = null; // Returns a SuspenseInstance or Container if it's blocked. -// The return_targetInst field above is conceptually part of the return value. - -function findInstanceBlockingEvent( - domEventName, - eventSystemFlags, - targetContainer, - nativeEvent -) { - // TODO: Warn if _enabled is false. - return_targetInst = null; - var nativeEventTarget = getEventTarget(nativeEvent); - var targetInst = getClosestInstanceFromNode(nativeEventTarget); - - if (targetInst !== null) { - var nearestMounted = getNearestMountedFiber(targetInst); - - if (nearestMounted === null) { - // This tree has been unmounted already. Dispatch without a target. - targetInst = null; - } else { - var tag = nearestMounted.tag; +function popTreeContext(workInProgress) { + // Restore the previous values. + // This is a bit more complicated than other context-like modules in Fiber + // because the same Fiber may appear on the stack multiple times and for + // different reasons. We have to keep popping until the work-in-progress is + // no longer at the top of the stack. + while (workInProgress === treeForkProvider) { + treeForkProvider = forkStack[--forkStackIndex]; + forkStack[forkStackIndex] = null; + treeForkCount = forkStack[--forkStackIndex]; + forkStack[forkStackIndex] = null; + } - if (tag === SuspenseComponent) { - var instance = getSuspenseInstanceFromFiber(nearestMounted); + while (workInProgress === treeContextProvider) { + treeContextProvider = idStack[--idStackIndex]; + idStack[idStackIndex] = null; + treeContextOverflow = idStack[--idStackIndex]; + idStack[idStackIndex] = null; + treeContextId = idStack[--idStackIndex]; + idStack[idStackIndex] = null; + } +} +function getSuspendedTreeContext() { + warnIfNotHydrating(); - if (instance !== null) { - // Queue the event to be replayed later. Abort dispatching since we - // don't want this event dispatched twice through the event system. - // TODO: If this is the first discrete event in the queue. Schedule an increased - // priority for this boundary. - return instance; - } // This shouldn't happen, something went wrong but to avoid blocking - // the whole system, dispatch the event without a target. - // TODO: Warn. + if (treeContextProvider !== null) { + return { + id: treeContextId, + overflow: treeContextOverflow + }; + } else { + return null; + } +} +function restoreSuspendedTreeContext(workInProgress, suspendedContext) { + warnIfNotHydrating(); + idStack[idStackIndex++] = treeContextId; + idStack[idStackIndex++] = treeContextOverflow; + idStack[idStackIndex++] = treeContextProvider; + treeContextId = suspendedContext.id; + treeContextOverflow = suspendedContext.overflow; + treeContextProvider = workInProgress; +} - targetInst = null; - } else if (tag === HostRoot) { - var root = nearestMounted.stateNode; +function warnIfNotHydrating() { + { + if (!getIsHydrating()) { + error( + "Expected to be hydrating. This is a bug in React. Please file " + + "an issue." + ); + } + } +} - if (isRootDehydrated(root)) { - // If this happens during a replay something went wrong and it might block - // the whole system. - return getContainerFromFiber(nearestMounted); - } +var contextStackCursor = createCursor(null); +var contextFiberStackCursor = createCursor(null); +var rootInstanceStackCursor = createCursor(null); - targetInst = null; - } else if (nearestMounted !== targetInst) { - // If we get an event (ex: img onload) before committing that - // component's mount, ignore it for now (that is, treat it as if it was an - // event on a non-React tree). We might also consider queueing events and - // dispatching them after the mount. - targetInst = null; - } +function requiredContext(c) { + { + if (c === null) { + error( + "Expected host context to exist. This error is likely caused by a bug " + + "in React. Please file an issue." + ); } } - return_targetInst = targetInst; // We're not blocked on anything. - - return null; + return c; } -function getEventPriority(domEventName) { - switch (domEventName) { - // Used by SimpleEventPlugin: - case "cancel": - case "click": - case "close": - case "contextmenu": - case "copy": - case "cut": - case "auxclick": - case "dblclick": - case "dragend": - case "dragstart": - case "drop": - case "focusin": - case "focusout": - case "input": - case "invalid": - case "keydown": - case "keypress": - case "keyup": - case "mousedown": - case "mouseup": - case "paste": - case "pause": - case "play": - case "pointercancel": - case "pointerdown": - case "pointerup": - case "ratechange": - case "reset": - case "resize": - case "seeked": - case "submit": - case "touchcancel": - case "touchend": - case "touchstart": - case "volumechange": // Used by polyfills: - // eslint-disable-next-line no-fallthrough - case "change": - case "selectionchange": - case "textInput": - case "compositionstart": - case "compositionend": - case "compositionupdate": // Only enableCreateEventHandleAPI: - // eslint-disable-next-line no-fallthrough +function getCurrentRootHostContainer() { + return rootInstanceStackCursor.current; +} - case "beforeblur": - case "afterblur": // Not used by React but could be by user code: - // eslint-disable-next-line no-fallthrough +function getRootHostContainer() { + var rootInstance = requiredContext(rootInstanceStackCursor.current); + return rootInstance; +} - case "beforeinput": - case "blur": - case "fullscreenchange": - case "focus": - case "hashchange": - case "popstate": - case "select": - case "selectstart": - return DiscreteEventPriority; +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. - case "drag": - case "dragenter": - case "dragexit": - case "dragleave": - case "dragover": - case "mousemove": - case "mouseout": - case "mouseover": - case "pointermove": - case "pointerout": - case "pointerover": - case "scroll": - case "toggle": - case "touchmove": - case "wheel": // Not used by React but could be by user code: - // eslint-disable-next-line no-fallthrough + 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. - case "mouseenter": - case "mouseleave": - case "pointerenter": - case "pointerleave": - return ContinuousEventPriority; + push(contextStackCursor, null, fiber); + var nextRootContext = getRootHostContext(nextRootInstance); // Now that we know this function doesn't throw, replace it. - case "message": { - // We might be in the Scheduler callback. - // Eventually this mechanism will be replaced by a check - // of the current priority on the native scheduler. - var schedulerPriority = getCurrentPriorityLevel(); + pop(contextStackCursor, fiber); + push(contextStackCursor, nextRootContext, fiber); +} - switch (schedulerPriority) { - case ImmediatePriority: - return DiscreteEventPriority; +function popHostContainer(fiber) { + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); + pop(rootInstanceStackCursor, fiber); +} - case UserBlockingPriority: - return ContinuousEventPriority; +function getHostContext() { + var context = requiredContext(contextStackCursor.current); + return context; +} - case NormalPriority$1: - case LowPriority: - // TODO: Handle LowSchedulerPriority, somehow. Maybe the same lane as hydration. - return DefaultEventPriority; +function pushHostContext(fiber) { + var context = requiredContext(contextStackCursor.current); + var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique. - case IdlePriority: - return IdleEventPriority; + if (context === nextContext) { + return; + } // Track the context and the Fiber that provided it. + // This enables us to pop only Fibers that provide unique contexts. - default: - return DefaultEventPriority; - } - } + push(contextFiberStackCursor, fiber, fiber); + push(contextStackCursor, nextContext, fiber); +} - default: - return DefaultEventPriority; +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; } -} -function addEventBubbleListener(target, eventType, listener) { - target.addEventListener(eventType, listener, false); - return listener; -} -function addEventCaptureListener(target, eventType, listener) { - target.addEventListener(eventType, listener, true); - return listener; -} -function addEventCaptureListenerWithPassiveFlag( - target, - eventType, - listener, - passive -) { - target.addEventListener(eventType, listener, { - capture: true, - passive: passive - }); - return listener; -} -function addEventBubbleListenerWithPassiveFlag( - target, - eventType, - listener, - passive -) { - target.addEventListener(eventType, listener, { - passive: passive - }); - return listener; -} -function removeEventListener(target, eventType, listener, capture) { - target.removeEventListener(eventType, listener, capture); + pop(contextStackCursor, fiber); + pop(contextFiberStackCursor, fiber); } -/** - * These variables store information about text content of a target node, - * allowing comparison of content before and after a given event. - * - * Identify the node where selection currently begins, then observe - * both its text content and its current position in the DOM. Since the - * browser may natively replace the target node during composition, we can - * use its position to find its replacement. - * - * - */ -var root = null; -var startText = null; -var fallbackText = null; -function initialize(nativeEventTarget) { - root = nativeEventTarget; - startText = getText(); - return true; -} -function reset() { - root = null; - startText = null; - fallbackText = null; -} -function getData() { - if (fallbackText) { - return fallbackText; - } +// This may have been an insertion or a hydration. - var start; - var startValue = startText; - var startLength = startValue.length; - var end; - var endValue = getText(); - var endLength = endValue.length; +var hydrationParentFiber = null; +var nextHydratableInstance = null; +var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches +// due to earlier mismatches or a suspended fiber. - for (start = 0; start < startLength; start++) { - if (startValue[start] !== endValue[start]) { - break; - } - } +var didSuspendOrErrorDEV = false; // Hydration errors that were thrown inside this boundary - var minEnd = startLength - start; +var hydrationErrors = null; +var rootOrSingletonContext = false; - for (end = 1; end <= minEnd; end++) { - if (startValue[startLength - end] !== endValue[endLength - end]) { - break; +function warnIfHydrating() { + { + if (isHydrating) { + error( + "We should not be hydrating here. This is a bug in React. Please file a bug." + ); } } +} - var sliceTail = end > 1 ? 1 - end : undefined; - fallbackText = endValue.slice(start, sliceTail); - return fallbackText; +function markDidThrowWhileHydratingDEV() { + { + didSuspendOrErrorDEV = true; + } } -function getText() { - if ("value" in root) { - return root.value; +function didSuspendOrErrorWhileHydratingDEV() { + { + return didSuspendOrErrorDEV; } - - return root.textContent; } -/** - * `charCode` represents the actual "character code" and is safe to use with - * `String.fromCharCode`. As such, only keys that correspond to printable - * characters produce a valid `charCode`, the only exception to this is Enter. - * The Tab-key is considered non-printable and does not have a `charCode`, - * presumably because it does not produce a tab-character in browsers. - * - * @param {object} nativeEvent Native browser event. - * @return {number} Normalized `charCode` property. - */ -function getEventCharCode(nativeEvent) { - var charCode; - var keyCode = nativeEvent.keyCode; - - if ("charCode" in nativeEvent) { - charCode = nativeEvent.charCode; // FF does not set `charCode` for the Enter-key, check against `keyCode`. - - if (charCode === 0 && keyCode === 13) { - charCode = 13; - } - } else { - // IE8 does not implement `charCode`, but `keyCode` has the correct value. - charCode = keyCode; - } // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux) - // report Enter as charCode 10 when ctrl is pressed. +function enterHydrationState(fiber) { + var parentInstance = fiber.stateNode.containerInfo; + nextHydratableInstance = + getFirstHydratableChildWithinContainer(parentInstance); + hydrationParentFiber = fiber; + isHydrating = true; + hydrationErrors = null; + didSuspendOrErrorDEV = false; + rootOrSingletonContext = true; + return true; +} - if (charCode === 10) { - charCode = 13; - } // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. - // Must not discard the (non-)printable Enter-key. +function reenterHydrationStateFromDehydratedSuspenseInstance( + fiber, + suspenseInstance, + treeContext +) { + nextHydratableInstance = + getFirstHydratableChildWithinSuspenseInstance(suspenseInstance); + hydrationParentFiber = fiber; + isHydrating = true; + hydrationErrors = null; + didSuspendOrErrorDEV = false; + rootOrSingletonContext = false; - if (charCode >= 32 || charCode === 13) { - return charCode; + if (treeContext !== null) { + restoreSuspendedTreeContext(fiber, treeContext); } - return 0; -} - -function functionThatReturnsTrue() { return true; } -function functionThatReturnsFalse() { - return false; -} // This is intentionally a factory so that we have different returned constructors. -// If we had a single constructor, it would be megamorphic and engines would deopt. - -function createSyntheticEvent(Interface) { - /** - * Synthetic events are dispatched by event plugins, typically in response to a - * top-level event delegation handler. - * - * These systems should generally use pooling to reduce the frequency of garbage - * collection. The system should check `isPersistent` to determine whether the - * event should be released into the pool after being dispatched. Users that - * need a persisted event should invoke `persist`. - * - * Synthetic events (and subclasses) implement the DOM Level 3 Events API by - * normalizing browser quirks. Subclasses do not necessarily have to implement a - * DOM interface; custom application-specific events can also subclass this. - */ - // $FlowFixMe[missing-this-annot] - function SyntheticBaseEvent( - reactName, - reactEventType, - targetInst, - nativeEvent, - nativeEventTarget - ) { - this._reactName = reactName; - this._targetInst = targetInst; - this.type = reactEventType; - this.nativeEvent = nativeEvent; - this.target = nativeEventTarget; - this.currentTarget = null; - - for (var propName in Interface) { - if (!Interface.hasOwnProperty(propName)) { - continue; +function warnUnhydratedInstance(returnFiber, instance) { + { + switch (returnFiber.tag) { + case HostRoot: { + didNotHydrateInstanceWithinContainer( + returnFiber.stateNode.containerInfo, + instance + ); + break; } - var normalize = Interface[propName]; + case HostSingleton: + case HostComponent: { + var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode; + didNotHydrateInstance( + returnFiber.type, + returnFiber.memoizedProps, + returnFiber.stateNode, + instance, // TODO: Delete this argument when we remove the legacy root API. + isConcurrentMode + ); + break; + } - if (normalize) { - this[propName] = normalize(nativeEvent); - } else { - this[propName] = nativeEvent[propName]; + case SuspenseComponent: { + var suspenseState = returnFiber.memoizedState; + if (suspenseState.dehydrated !== null) + didNotHydrateInstanceWithinSuspenseInstance( + suspenseState.dehydrated, + instance + ); + break; } } + } +} - var defaultPrevented = - nativeEvent.defaultPrevented != null - ? nativeEvent.defaultPrevented - : nativeEvent.returnValue === false; +function deleteHydratableInstance(returnFiber, instance) { + warnUnhydratedInstance(returnFiber, instance); + var childToDelete = createFiberFromHostInstanceForDeletion(); + childToDelete.stateNode = instance; + childToDelete.return = returnFiber; + var deletions = returnFiber.deletions; - if (defaultPrevented) { - this.isDefaultPrevented = functionThatReturnsTrue; - } else { - this.isDefaultPrevented = functionThatReturnsFalse; - } - - this.isPropagationStopped = functionThatReturnsFalse; - return this; - } // $FlowFixMe[prop-missing] found when upgrading Flow + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } +} - assign(SyntheticBaseEvent.prototype, { - // $FlowFixMe[missing-this-annot] - preventDefault: function () { - this.defaultPrevented = true; - var event = this.nativeEvent; +function warnNonhydratedInstance(returnFiber, fiber) { + { + if (didSuspendOrErrorDEV) { + // Inside a boundary that already suspended. We're currently rendering the + // siblings of a suspended node. The mismatch may be due to the missing + // data, so it's probably a false positive. + return; + } - if (!event) { - return; - } + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; - if (event.preventDefault) { - event.preventDefault(); // $FlowFixMe - flow is not aware of `unknown` in IE - } else if (typeof event.returnValue !== "unknown") { - event.returnValue = false; - } + switch (fiber.tag) { + case HostSingleton: + case HostComponent: + var type = fiber.type; + didNotFindHydratableInstanceWithinContainer(parentContainer, type); + break; - this.isDefaultPrevented = functionThatReturnsTrue; - }, - // $FlowFixMe[missing-this-annot] - stopPropagation: function () { - var event = this.nativeEvent; + case HostText: + var text = fiber.pendingProps; + didNotFindHydratableTextInstanceWithinContainer( + parentContainer, + text + ); + break; + } - if (!event) { - return; + break; } - if (event.stopPropagation) { - event.stopPropagation(); // $FlowFixMe - flow is not aware of `unknown` in IE - } else if (typeof event.cancelBubble !== "unknown") { - // The ChangeEventPlugin registers a "propertychange" event for - // IE. This event does not support bubbling or cancelling, and - // any references to cancelBubble throw "Member not found". A - // typeof check of "unknown" circumvents this issue (and is also - // IE specific). - event.cancelBubble = true; - } + case HostSingleton: + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; - this.isPropagationStopped = functionThatReturnsTrue; - }, + switch (fiber.tag) { + case HostSingleton: + case HostComponent: { + var _type = fiber.type; + var _props = fiber.pendingProps; + var isConcurrentMode = + (returnFiber.mode & ConcurrentMode) !== NoMode; + didNotFindHydratableInstance( + parentType, + parentProps, + parentInstance, + _type, + _props, // TODO: Delete this argument when we remove the legacy root API. + isConcurrentMode + ); + break; + } - /** - * We release all dispatched `SyntheticEvent`s after each event loop, adding - * them back into the pool. This allows a way to hold onto a reference that - * won't be added back into the pool. - */ - persist: function () { - // Modern event system doesn't use pooling. - }, + case HostText: { + var _text = fiber.pendingProps; - /** - * Checks if this event should be released back into the pool. - * - * @return {boolean} True if this should not be released, false otherwise. - */ - isPersistent: functionThatReturnsTrue - }); - return SyntheticBaseEvent; -} -/** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ + var _isConcurrentMode = + (returnFiber.mode & ConcurrentMode) !== NoMode; -var EventInterface = { - eventPhase: 0, - bubbles: 0, - cancelable: 0, - timeStamp: function (event) { - return event.timeStamp || Date.now(); - }, - defaultPrevented: 0, - isTrusted: 0 -}; -var SyntheticEvent = createSyntheticEvent(EventInterface); + didNotFindHydratableTextInstance( + parentType, + parentProps, + parentInstance, + _text, // TODO: Delete this argument when we remove the legacy root API. + _isConcurrentMode + ); + break; + } + } -var UIEventInterface = assign({}, EventInterface, { - view: 0, - detail: 0 -}); + break; + } -var SyntheticUIEvent = createSyntheticEvent(UIEventInterface); -var lastMovementX; -var lastMovementY; -var lastMouseEvent; + case SuspenseComponent: { + var suspenseState = returnFiber.memoizedState; + var _parentInstance = suspenseState.dehydrated; + if (_parentInstance !== null) + switch (fiber.tag) { + case HostSingleton: + case HostComponent: + var _type2 = fiber.type; + didNotFindHydratableInstanceWithinSuspenseInstance( + _parentInstance, + _type2 + ); + break; -function updateMouseMovementPolyfillState(event) { - if (event !== lastMouseEvent) { - if (lastMouseEvent && event.type === "mousemove") { - // $FlowFixMe assuming this is a number - lastMovementX = event.screenX - lastMouseEvent.screenX; // $FlowFixMe assuming this is a number + case HostText: + var _text2 = fiber.pendingProps; + didNotFindHydratableTextInstanceWithinSuspenseInstance( + _parentInstance, + _text2 + ); + break; + } + break; + } - lastMovementY = event.screenY - lastMouseEvent.screenY; - } else { - lastMovementX = 0; - lastMovementY = 0; + default: + return; } - - lastMouseEvent = event; } } -/** - * @interface MouseEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var MouseEventInterface = assign({}, UIEventInterface, { - screenX: 0, - screenY: 0, - clientX: 0, - clientY: 0, - pageX: 0, - pageY: 0, - ctrlKey: 0, - shiftKey: 0, - altKey: 0, - metaKey: 0, - getModifierState: getEventModifierState, - button: 0, - buttons: 0, - relatedTarget: function (event) { - if (event.relatedTarget === undefined) - return event.fromElement === event.srcElement - ? event.toElement - : event.fromElement; - return event.relatedTarget; - }, - movementX: function (event) { - if ("movementX" in event) { - return event.movementX; - } +function insertNonHydratedInstance(returnFiber, fiber) { + fiber.flags = (fiber.flags & ~Hydrating) | Placement; + warnNonhydratedInstance(returnFiber, fiber); +} - updateMouseMovementPolyfillState(event); - return lastMovementX; - }, - movementY: function (event) { - if ("movementY" in event) { - return event.movementY; - } // Don't need to call updateMouseMovementPolyfillState() here - // because it's guaranteed to have already run when movementX - // was copied. +function tryHydrateInstance(fiber, nextInstance) { + // fiber is a HostComponent Fiber + var instance = canHydrateInstance(nextInstance, fiber.type); - return lastMovementY; + if (instance !== null) { + fiber.stateNode = instance; + hydrationParentFiber = fiber; + nextHydratableInstance = getFirstHydratableChild(instance); + rootOrSingletonContext = false; + return true; } -}); - -var SyntheticMouseEvent = createSyntheticEvent(MouseEventInterface); -/** - * @interface DragEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ - -var DragEventInterface = assign({}, MouseEventInterface, { - dataTransfer: 0 -}); - -var SyntheticDragEvent = createSyntheticEvent(DragEventInterface); -/** - * @interface FocusEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ -var FocusEventInterface = assign({}, UIEventInterface, { - relatedTarget: 0 -}); - -var SyntheticFocusEvent = createSyntheticEvent(FocusEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface - * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent - */ + return false; +} -var AnimationEventInterface = assign({}, EventInterface, { - animationName: 0, - elapsedTime: 0, - pseudoElement: 0 -}); +function tryHydrateText(fiber, nextInstance) { + // fiber is a HostText Fiber + var text = fiber.pendingProps; + var textInstance = canHydrateTextInstance(nextInstance, text); -var SyntheticAnimationEvent = createSyntheticEvent(AnimationEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/clipboard-apis/ - */ + if (textInstance !== null) { + fiber.stateNode = textInstance; + hydrationParentFiber = fiber; // Text Instances don't have children so there's nothing to hydrate. -var ClipboardEventInterface = assign({}, EventInterface, { - clipboardData: function (event) { - return "clipboardData" in event - ? event.clipboardData - : window.clipboardData; + nextHydratableInstance = null; + return true; } -}); -var SyntheticClipboardEvent = createSyntheticEvent(ClipboardEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents - */ + return false; +} -var CompositionEventInterface = assign({}, EventInterface, { - data: 0 -}); +function tryHydrateSuspense(fiber, nextInstance) { + // fiber is a SuspenseComponent Fiber + var suspenseInstance = canHydrateSuspenseInstance(nextInstance); -var SyntheticCompositionEvent = createSyntheticEvent(CompositionEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 - * /#events-inputevents - */ -// Happens to share the same list for now. + if (suspenseInstance !== null) { + var suspenseState = { + dehydrated: suspenseInstance, + treeContext: getSuspendedTreeContext(), + retryLane: OffscreenLane + }; + fiber.memoizedState = suspenseState; // Store the dehydrated fragment as a child fiber. + // This simplifies the code for getHostSibling and deleting nodes, + // since it doesn't have to consider all Suspense boundaries and + // check if they're dehydrated ones or not. -var SyntheticInputEvent = SyntheticCompositionEvent; -/** - * Normalization of deprecated HTML5 `key` values - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ + var dehydratedFragment = + createFiberFromDehydratedFragment(suspenseInstance); + dehydratedFragment.return = fiber; + fiber.child = dehydratedFragment; + hydrationParentFiber = fiber; // While a Suspense Instance does have children, we won't step into + // it during the first pass. Instead, we'll reenter it later. -var normalizeKey = { - Esc: "Escape", - Spacebar: " ", - Left: "ArrowLeft", - Up: "ArrowUp", - Right: "ArrowRight", - Down: "ArrowDown", - Del: "Delete", - Win: "OS", - Menu: "ContextMenu", - Apps: "ContextMenu", - Scroll: "ScrollLock", - MozPrintableKey: "Unidentified" -}; -/** - * Translation from legacy `keyCode` to HTML5 `key` - * Only special keys supported, all others depend on keyboard layout or browser - * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names - */ + nextHydratableInstance = null; + return true; + } -var translateToKey = { - "8": "Backspace", - "9": "Tab", - "12": "Clear", - "13": "Enter", - "16": "Shift", - "17": "Control", - "18": "Alt", - "19": "Pause", - "20": "CapsLock", - "27": "Escape", - "32": " ", - "33": "PageUp", - "34": "PageDown", - "35": "End", - "36": "Home", - "37": "ArrowLeft", - "38": "ArrowUp", - "39": "ArrowRight", - "40": "ArrowDown", - "45": "Insert", - "46": "Delete", - "112": "F1", - "113": "F2", - "114": "F3", - "115": "F4", - "116": "F5", - "117": "F6", - "118": "F7", - "119": "F8", - "120": "F9", - "121": "F10", - "122": "F11", - "123": "F12", - "144": "NumLock", - "145": "ScrollLock", - "224": "Meta" -}; -/** - * @param {object} nativeEvent Native browser event. - * @return {string} Normalized `key` property. - */ + return false; +} -function getEventKey(nativeEvent) { - if (nativeEvent.key) { - // Normalize inconsistent values reported by browsers due to - // implementations of a working draft specification. - // FireFox implements `key` but returns `MozPrintableKey` for all - // printable characters (normalized to `Unidentified`), ignore it. - var key = normalizeKey[nativeEvent.key] || nativeEvent.key; // $FlowFixMe unable to index with a `mixed` value +function shouldClientRenderOnMismatch(fiber) { + return ( + (fiber.mode & ConcurrentMode) !== NoMode && + (fiber.flags & DidCapture) === NoFlags$1 + ); +} - if (key !== "Unidentified") { - return key; - } - } // Browser does not implement `key`, polyfill as much of it as we can. +function throwOnHydrationMismatch(fiber) { + throw new Error( + "Hydration failed because the initial UI does not match what was " + + "rendered on the server." + ); +} - if (nativeEvent.type === "keypress") { - var charCode = getEventCharCode( - // $FlowFixMe unable to narrow to `KeyboardEvent` - nativeEvent - ); // The enter-key is technically both printable and non-printable and can - // thus be captured by `keypress`, no other non-printable key should. +function claimHydratableSingleton(fiber) { + { + if (!isHydrating) { + return; + } - return charCode === 13 ? "Enter" : String.fromCharCode(charCode); + var currentRootContainer = getRootHostContainer(); + var currentHostContext = getHostContext(); + var instance = (fiber.stateNode = resolveSingletonInstance( + fiber.type, + fiber.pendingProps, + currentRootContainer, + currentHostContext, + false + )); + hydrationParentFiber = fiber; + rootOrSingletonContext = true; + nextHydratableInstance = getFirstHydratableChild(instance); } +} - if (nativeEvent.type === "keydown" || nativeEvent.type === "keyup") { - // While user keyboard layout determines the actual meaning of each - // `keyCode` value, almost all function keys have a universal value. - // $FlowFixMe unable to index with a `mixed` value - return translateToKey[nativeEvent.keyCode] || "Unidentified"; +function advanceToFirstAttemptableInstance(fiber) { + // fiber is HostComponent Fiber + while ( + nextHydratableInstance && + shouldSkipHydratableForInstance( + nextHydratableInstance, + fiber.type, + fiber.pendingProps + ) + ) { + // Flow doesn't understand that inside this block nextHydratableInstance is not null + var instance = nextHydratableInstance; + nextHydratableInstance = getNextHydratableSibling(instance); } - - return ""; } -/** - * Translation from modifier key to the associated property in the event. - * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers - */ - -var modifierKeyToProp = { - Alt: "altKey", - Control: "ctrlKey", - Meta: "metaKey", - Shift: "shiftKey" -}; // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support -// getModifierState. If getModifierState is not supported, we map it to a set of -// modifier keys exposed by the event. In this case, Lock-keys are not supported. -// $FlowFixMe[missing-local-annot] -// $FlowFixMe[missing-this-annot] - -function modifierStateGetter(keyArg) { - var syntheticEvent = this; - var nativeEvent = syntheticEvent.nativeEvent; - if (nativeEvent.getModifierState) { - return nativeEvent.getModifierState(keyArg); +function advanceToFirstAttemptableTextInstance() { + while ( + nextHydratableInstance && + shouldSkipHydratableForTextInstance(nextHydratableInstance) + ) { + // Flow doesn't understand that inside this block nextHydratableInstance is not null + var instance = nextHydratableInstance; + nextHydratableInstance = getNextHydratableSibling(instance); } - - var keyProp = modifierKeyToProp[keyArg]; - return keyProp ? !!nativeEvent[keyProp] : false; } -function getEventModifierState(nativeEvent) { - return modifierStateGetter; +function advanceToFirstAttemptableSuspenseInstance() { + while ( + nextHydratableInstance && + shouldSkipHydratableForSuspenseInstance(nextHydratableInstance) + ) { + // Flow doesn't understand that inside this block nextHydratableInstance is not null + var instance = nextHydratableInstance; + nextHydratableInstance = getNextHydratableSibling(instance); + } } -/** - * @interface KeyboardEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ - -var KeyboardEventInterface = assign({}, UIEventInterface, { - key: getEventKey, - code: 0, - location: 0, - ctrlKey: 0, - shiftKey: 0, - altKey: 0, - metaKey: 0, - repeat: 0, - locale: 0, - getModifierState: getEventModifierState, - // Legacy Interface - charCode: function (event) { - // `charCode` is the result of a KeyPress event and represents the value of - // the actual printable character. - // KeyPress is deprecated, but its replacement is not yet final and not - // implemented in any major browser. Only KeyPress has charCode. - if (event.type === "keypress") { - return getEventCharCode( - // $FlowFixMe unable to narrow to `KeyboardEvent` - event - ); - } - return 0; - }, - keyCode: function (event) { - // `keyCode` is the result of a KeyDown/Up event and represents the value of - // physical keyboard key. - // The actual meaning of the value depends on the users' keyboard layout - // which cannot be detected. Assuming that it is a US keyboard layout - // provides a surprisingly accurate mapping for US and European users. - // Due to this, it is left to the user to implement at this time. - if (event.type === "keydown" || event.type === "keyup") { - return event.keyCode; - } +function tryToClaimNextHydratableInstance(fiber) { + if (!isHydrating) { + return; + } - return 0; - }, - which: function (event) { - // `which` is an alias for either `keyCode` or `charCode` depending on the - // type of the event. - if (event.type === "keypress") { - return getEventCharCode( - // $FlowFixMe unable to narrow to `KeyboardEvent` - event - ); + { + if (!isHydratableType(fiber.type, fiber.pendingProps)) { + // This fiber never hydrates from the DOM and always does an insert + fiber.flags = (fiber.flags & ~Hydrating) | Placement; + isHydrating = false; + hydrationParentFiber = fiber; + return; } + } - if (event.type === "keydown" || event.type === "keyup") { - return event.keyCode; - } + var initialInstance = nextHydratableInstance; - return 0; + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableInstance(fiber); } -}); -var SyntheticKeyboardEvent = createSyntheticEvent(KeyboardEventInterface); -/** - * @interface PointerEvent - * @see http://www.w3.org/TR/pointerevents/ - */ + var nextInstance = nextHydratableInstance; -var PointerEventInterface = assign({}, MouseEventInterface, { - pointerId: 0, - width: 0, - height: 0, - pressure: 0, - tangentialPressure: 0, - tiltX: 0, - tiltY: 0, - twist: 0, - pointerType: 0, - isPrimary: 0 -}); + if (!nextInstance) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // Nothing to hydrate. Make it an insertion. -var SyntheticPointerEvent = createSyntheticEvent(PointerEventInterface); -/** - * @interface TouchEvent - * @see http://www.w3.org/TR/touch-events/ - */ + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + return; + } -var TouchEventInterface = assign({}, UIEventInterface, { - touches: 0, - targetTouches: 0, - changedTouches: 0, - altKey: 0, - metaKey: 0, - ctrlKey: 0, - shiftKey: 0, - getModifierState: getEventModifierState -}); + var firstAttemptedInstance = nextInstance; -var SyntheticTouchEvent = createSyntheticEvent(TouchEventInterface); -/** - * @interface Event - * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- - * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent - */ + if (!tryHydrateInstance(fiber, nextInstance)) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // 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. -var TransitionEventInterface = assign({}, EventInterface, { - propertyName: 0, - elapsedTime: 0, - pseudoElement: 0 -}); + nextHydratableInstance = getNextHydratableSibling(nextInstance); + var prevHydrationParentFiber = hydrationParentFiber; -var SyntheticTransitionEvent = createSyntheticEvent(TransitionEventInterface); -/** - * @interface WheelEvent - * @see http://www.w3.org/TR/DOM-Level-3-Events/ - */ + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableInstance(fiber); + } -var WheelEventInterface = assign({}, MouseEventInterface, { - deltaX: function (event) { - return "deltaX" in event - ? event.deltaX // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). - : "wheelDeltaX" in event // $FlowFixMe assuming this is a number - ? -event.wheelDeltaX - : 0; - }, - deltaY: function (event) { - return "deltaY" in event - ? event.deltaY // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). - : "wheelDeltaY" in event // $FlowFixMe assuming this is a number - ? -event.wheelDeltaY // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). - : "wheelDelta" in event // $FlowFixMe assuming this is a number - ? -event.wheelDelta - : 0; - }, - deltaZ: 0, - // Browsers without "deltaMode" is reporting in raw wheel delta where one - // notch on the scroll is always +/- 120, roughly equivalent to pixels. - // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or - // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. - deltaMode: 0 -}); + if ( + !nextHydratableInstance || + !tryHydrateInstance(fiber, nextHydratableInstance) + ) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + 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. -var SyntheticWheelEvent = createSyntheticEvent(WheelEventInterface); + deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); + } +} -var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space +function tryToClaimNextHydratableTextInstance(fiber) { + if (!isHydrating) { + return; + } -var START_KEYCODE = 229; -var canUseCompositionEvent = canUseDOM && "CompositionEvent" in window; -var documentMode = null; + var text = fiber.pendingProps; + var isHydratable = isHydratableText(text); + var initialInstance = nextHydratableInstance; -if (canUseDOM && "documentMode" in document) { - documentMode = document.documentMode; -} // Webkit offers a very useful `textInput` event that can be used to -// directly represent `beforeInput`. The IE `textinput` event is not as -// useful, so we don't use it. + if (rootOrSingletonContext && isHydratable) { + // We may need to skip past certain nodes in these contexts. + // We don't skip if the text is not hydratable because we know no hydratables + // exist which could match this Fiber + advanceToFirstAttemptableTextInstance(); + } -var canUseTextInputEvent = canUseDOM && "TextEvent" in window && !documentMode; // In IE9+, we have access to composition events, but the data supplied -// by the native compositionend event may be incorrect. Japanese ideographic -// spaces, for instance (\u3000) are not recorded correctly. + var nextInstance = nextHydratableInstance; -var useFallbackCompositionData = - canUseDOM && - (!canUseCompositionEvent || - (documentMode && documentMode > 8 && documentMode <= 11)); -var SPACEBAR_CODE = 32; -var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); + if (!nextInstance || !isHydratable) { + // We exclude non hydrabable text because we know there are no matching hydratables. + // We either throw or insert depending on the render mode. + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // Nothing to hydrate. Make it an insertion. -function registerEvents$3() { - registerTwoPhaseEvent("onBeforeInput", [ - "compositionend", - "keypress", - "textInput", - "paste" - ]); - registerTwoPhaseEvent("onCompositionEnd", [ - "compositionend", - "focusout", - "keydown", - "keypress", - "keyup", - "mousedown" - ]); - registerTwoPhaseEvent("onCompositionStart", [ - "compositionstart", - "focusout", - "keydown", - "keypress", - "keyup", - "mousedown" - ]); - registerTwoPhaseEvent("onCompositionUpdate", [ - "compositionupdate", - "focusout", - "keydown", - "keypress", - "keyup", - "mousedown" - ]); -} // Track whether we've ever handled a keypress on the space key. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + return; + } -var hasSpaceKeypress = false; -/** - * Return whether a native keypress event is assumed to be a command. - * This is required because Firefox fires `keypress` events for key commands - * (cut, copy, select-all, etc.) even though no character is inserted. - */ + var firstAttemptedInstance = nextInstance; -function isKeypressCommand(nativeEvent) { - return ( - (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && // ctrlKey && altKey is equivalent to AltGr, and is not a command. - !(nativeEvent.ctrlKey && nativeEvent.altKey) - ); -} -/** - * Translate native top level events into event types. - */ + if (!tryHydrateText(fiber, nextInstance)) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // 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. -function getCompositionEventType(domEventName) { - switch (domEventName) { - case "compositionstart": - return "onCompositionStart"; + nextHydratableInstance = getNextHydratableSibling(nextInstance); + var prevHydrationParentFiber = hydrationParentFiber; - case "compositionend": - return "onCompositionEnd"; + if (rootOrSingletonContext && isHydratable) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableTextInstance(); + } - case "compositionupdate": - return "onCompositionUpdate"; - } -} -/** - * Does our fallback best-guess model think this event signifies that - * composition has begun? - */ + if ( + !nextHydratableInstance || + !tryHydrateText(fiber, nextHydratableInstance) + ) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + 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. -function isFallbackCompositionStart(domEventName, nativeEvent) { - return domEventName === "keydown" && nativeEvent.keyCode === START_KEYCODE; + deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); + } } -/** - * Does our fallback mode think that this event is the end of composition? - */ - -function isFallbackCompositionEnd(domEventName, nativeEvent) { - switch (domEventName) { - case "keyup": - // Command keys insert or clear IME input. - return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1; - case "keydown": - // Expect IME keyCode on each keydown. If we get any other - // code we must have exited earlier. - return nativeEvent.keyCode !== START_KEYCODE; +function tryToClaimNextHydratableSuspenseInstance(fiber) { + if (!isHydrating) { + return; + } - case "keypress": - case "mousedown": - case "focusout": - // Events are not possible without cancelling IME. - return true; + var initialInstance = nextHydratableInstance; - default: - return false; + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableSuspenseInstance(); } -} -/** - * Google Input Tools provides composition data via a CustomEvent, - * with the `data` property populated in the `detail` object. If this - * is available on the event object, use it. If not, this is a plain - * composition event and we have nothing special to extract. - * - * @param {object} nativeEvent - * @return {?string} - */ -function getDataFromCustomEvent(nativeEvent) { - var detail = nativeEvent.detail; + var nextInstance = nextHydratableInstance; - if (typeof detail === "object" && "data" in detail) { - return detail.data; - } + if (!nextInstance) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // Nothing to hydrate. Make it an insertion. - return null; -} -/** - * Check if a composition event was triggered by Korean IME. - * Our fallback mode does not work well with IE's Korean IME, - * so just use native composition events when Korean IME is used. - * Although CompositionEvent.locale property is deprecated, - * it is available in IE, where our fallback mode is enabled. - * - * @param {object} nativeEvent - * @return {boolean} - */ + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + return; + } -function isUsingKoreanIME(nativeEvent) { - return nativeEvent.locale === "ko"; -} // Track the current IME composition status, if any. + var firstAttemptedInstance = nextInstance; -var isComposing = false; -/** - * @return {?object} A SyntheticCompositionEvent. - */ + if (!tryHydrateSuspense(fiber, nextInstance)) { + if (shouldClientRenderOnMismatch(fiber)) { + warnNonhydratedInstance(hydrationParentFiber, fiber); + throwOnHydrationMismatch(); + } // 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. -function extractCompositionEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget -) { - var eventType; - var fallbackData; + nextHydratableInstance = getNextHydratableSibling(nextInstance); + var prevHydrationParentFiber = hydrationParentFiber; - if (canUseCompositionEvent) { - eventType = getCompositionEventType(domEventName); - } else if (!isComposing) { - if (isFallbackCompositionStart(domEventName, nativeEvent)) { - eventType = "onCompositionStart"; + if (rootOrSingletonContext) { + // We may need to skip past certain nodes in these contexts + advanceToFirstAttemptableSuspenseInstance(); } - } else if (isFallbackCompositionEnd(domEventName, nativeEvent)) { - eventType = "onCompositionEnd"; - } - if (!eventType) { - return null; - } + if ( + !nextHydratableInstance || + !tryHydrateSuspense(fiber, nextHydratableInstance) + ) { + // Nothing to hydrate. Make it an insertion. + insertNonHydratedInstance(hydrationParentFiber, fiber); + isHydrating = false; + hydrationParentFiber = fiber; + nextHydratableInstance = initialInstance; + 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. - if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) { - // The current composition is stored statically and must not be - // overwritten while composition continues. - if (!isComposing && eventType === "onCompositionStart") { - isComposing = initialize(nativeEventTarget); - } else if (eventType === "onCompositionEnd") { - if (isComposing) { - fallbackData = getData(); - } - } + deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance); } +} - var listeners = accumulateTwoPhaseListeners(targetInst, eventType); - - if (listeners.length > 0) { - var event = new SyntheticCompositionEvent( - eventType, - domEventName, - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); +function prepareToHydrateHostInstance(fiber, hostContext) { + var instance = fiber.stateNode; + var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV; + var updatePayload = hydrateInstance( + instance, + fiber.type, + fiber.memoizedProps, + hostContext, + fiber, + shouldWarnIfMismatchDev + ); // TODO: Type this specific to this type of component. - if (fallbackData) { - // Inject data generated from fallback path into the synthetic event. - // This matches the property of native CompositionEventInterface. - // $FlowFixMe[incompatible-use] - event.data = fallbackData; - } else { - var customData = getDataFromCustomEvent(nativeEvent); + 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 (customData !== null) { - // $FlowFixMe[incompatible-use] - event.data = customData; - } - } + if (updatePayload !== null) { + return true; } + + return false; } -function getNativeBeforeInputChars(domEventName, nativeEvent) { - switch (domEventName) { - case "compositionend": - return getDataFromCustomEvent(nativeEvent); +function prepareToHydrateHostTextInstance(fiber) { + var textInstance = fiber.stateNode; + var textContent = fiber.memoizedProps; + var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV; + var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); - case "keypress": - /** - * If native `textInput` events are available, our goal is to make - * use of them. However, there is a special case: the spacebar key. - * In Webkit, preventing default on a spacebar `textInput` event - * cancels character insertion, but it *also* causes the browser - * to fall back to its default spacebar behavior of scrolling the - * page. - * - * Tracking at: - * https://code.google.com/p/chromium/issues/detail?id=355103 - * - * To avoid this issue, use the keypress event as if no `textInput` - * event is available. - */ - var which = nativeEvent.which; + if (shouldUpdate) { + // We assume that prepareToHydrateHostTextInstance is called in a context where the + // hydration parent is the parent host component of this host text. + var returnFiber = hydrationParentFiber; - if (which !== SPACEBAR_CODE) { - return null; - } + if (returnFiber !== null) { + switch (returnFiber.tag) { + case HostRoot: { + var parentContainer = returnFiber.stateNode.containerInfo; + var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode; + didNotMatchHydratedContainerTextInstance( + parentContainer, + textInstance, + textContent, // TODO: Delete this argument when we remove the legacy root API. + isConcurrentMode, + shouldWarnIfMismatchDev + ); + break; + } - hasSpaceKeypress = true; - return SPACEBAR_CHAR; + case HostSingleton: + case HostComponent: { + var parentType = returnFiber.type; + var parentProps = returnFiber.memoizedProps; + var parentInstance = returnFiber.stateNode; - case "textInput": - // Record the characters to be added to the DOM. - var chars = nativeEvent.data; // If it's a spacebar character, assume that we have already handled - // it at the keypress level and bail immediately. Android Chrome - // doesn't give us keycodes, so we need to ignore it. + var _isConcurrentMode2 = + (returnFiber.mode & ConcurrentMode) !== NoMode; - if (chars === SPACEBAR_CHAR && hasSpaceKeypress) { - return null; + didNotMatchHydratedTextInstance( + parentType, + parentProps, + parentInstance, + textInstance, + textContent, // TODO: Delete this argument when we remove the legacy root API. + _isConcurrentMode2, + shouldWarnIfMismatchDev + ); + break; + } } + } + } - return chars; + return shouldUpdate; +} - default: - // For other native event types, do nothing. - return null; +function prepareToHydrateHostSuspenseInstance(fiber) { + var suspenseState = fiber.memoizedState; + var suspenseInstance = + suspenseState !== null ? suspenseState.dehydrated : null; + + if (!suspenseInstance) { + throw new Error( + "Expected to have a hydrated suspense instance. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } + + hydrateSuspenseInstance(suspenseInstance, fiber); } -/** - * For browsers that do not provide the `textInput` event, extract the - * appropriate string to use for SyntheticInputEvent. - */ -function getFallbackBeforeInputChars(domEventName, nativeEvent) { - // If we are currently composing (IME) and using a fallback to do so, - // try to extract the composed characters from the fallback object. - // If composition event is available, we extract a string only at - // compositionevent, otherwise extract it at fallback events. - if (isComposing) { - if ( - domEventName === "compositionend" || - (!canUseCompositionEvent && - isFallbackCompositionEnd(domEventName, nativeEvent)) - ) { - var chars = getData(); - reset(); - isComposing = false; - return chars; - } +function skipPastDehydratedSuspenseInstance(fiber) { + var suspenseState = fiber.memoizedState; + var suspenseInstance = + suspenseState !== null ? suspenseState.dehydrated : null; - return null; + if (!suspenseInstance) { + throw new Error( + "Expected to have a hydrated suspense instance. " + + "This error is likely caused by a bug in React. Please file an issue." + ); } - switch (domEventName) { - case "paste": - // If a paste event occurs after a keypress, throw out the input - // chars. Paste events should not lead to BeforeInput events. - return null; + return getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); +} - case "keypress": - /** - * As of v27, Firefox may fire keypress events even when no character - * will be inserted. A few possibilities: - * - * - `which` is `0`. Arrow keys, Esc key, etc. - * - * - `which` is the pressed key code, but no char is available. - * Ex: 'AltGr + d` in Polish. There is no modified character for - * this key combination and no character is inserted into the - * document, but FF fires the keypress for char code `100` anyway. - * No `input` event will occur. - * - * - `which` is the pressed key code, but a command combination is - * being used. Ex: `Cmd+C`. No character is inserted, and no - * `input` event will occur. - */ - if (!isKeypressCommand(nativeEvent)) { - // IE fires the `keypress` event when a user types an emoji via - // Touch keyboard of Windows. In such a case, the `char` property - // holds an emoji character like `\uD83D\uDE0A`. Because its length - // is 2, the property `which` does not represent an emoji correctly. - // In such a case, we directly return the `char` property instead of - // using `which`. - if (nativeEvent.char && nativeEvent.char.length > 1) { - return nativeEvent.char; - } else if (nativeEvent.which) { - return String.fromCharCode(nativeEvent.which); - } - } +function popToNextHostParent(fiber) { + hydrationParentFiber = fiber.return; - return null; + while (hydrationParentFiber) { + switch (hydrationParentFiber.tag) { + case HostRoot: + case HostSingleton: + rootOrSingletonContext = true; + return; - case "compositionend": - return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) - ? null - : nativeEvent.data; + case HostComponent: + case SuspenseComponent: + rootOrSingletonContext = false; + return; - default: - return null; + default: + hydrationParentFiber = hydrationParentFiber.return; + } } } -/** - * Extract a SyntheticInputEvent for `beforeInput`, based on either native - * `textInput` or fallback behavior. - * - * @return {?object} A SyntheticInputEvent. - */ - -function extractBeforeInputEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget -) { - var chars; - - if (canUseTextInputEvent) { - chars = getNativeBeforeInputChars(domEventName, nativeEvent); - } else { - chars = getFallbackBeforeInputChars(domEventName, nativeEvent); - } // If no characters are being inserted, no BeforeInput event should - // be fired. - if (!chars) { - return null; +function popHydrationState(fiber) { + if (fiber !== hydrationParentFiber) { + // We're deeper than the current hydration context, inside an inserted + // tree. + return false; } - var listeners = accumulateTwoPhaseListeners(targetInst, "onBeforeInput"); + 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; + } - if (listeners.length > 0) { - var event = new SyntheticInputEvent( - "onBeforeInput", - "beforeinput", - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); // $FlowFixMe[incompatible-use] + var shouldClear = false; - event.data = chars; + { + // With float we never clear the Root, or Singleton instances. We also do not clear Instances + // that have singleton text content + if ( + fiber.tag !== HostRoot && + fiber.tag !== HostSingleton && + !( + fiber.tag === HostComponent && + shouldSetTextContent(fiber.type, fiber.memoizedProps) + ) + ) { + shouldClear = true; + } } -} -/** - * Create an `onBeforeInput` event to match - * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents. - * - * This event plugin is based on the native `textInput` event - * available in Chrome, Safari, Opera, and IE. This event fires after - * `onKeyPress` and `onCompositionEnd`, but before `onInput`. - * - * `beforeInput` is spec'd but not implemented in any browsers, and - * the `input` event does not provide any useful information about what has - * actually been added, contrary to the spec. Thus, `textInput` is the best - * available event to identify the characters that have actually been inserted - * into the target node. - * - * This plugin is also responsible for emitting `composition` events, thus - * allowing us to share composition fallback code for both `beforeInput` and - * `composition` event types. - */ -function extractEvents$5( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - extractCompositionEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractBeforeInputEvent( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); -} + if (shouldClear) { + var nextInstance = nextHydratableInstance; -/** - * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary - */ -var supportedInputTypes = { - color: true, - date: true, - datetime: true, - "datetime-local": true, - email: true, - month: true, - number: true, - password: true, - range: true, - search: true, - tel: true, - text: true, - time: true, - url: true, - week: true -}; + if (nextInstance) { + if (shouldClientRenderOnMismatch(fiber)) { + warnIfUnhydratedTailNodes(fiber); + throwOnHydrationMismatch(); + } else { + while (nextInstance) { + deleteHydratableInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); + } + } + } + } -function isTextInputElement(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); + popToNextHostParent(fiber); - if (nodeName === "input") { - return !!supportedInputTypes[elem.type]; + if (fiber.tag === SuspenseComponent) { + nextHydratableInstance = skipPastDehydratedSuspenseInstance(fiber); + } else { + nextHydratableInstance = hydrationParentFiber + ? getNextHydratableSibling(fiber.stateNode) + : null; } - if (nodeName === "textarea") { - return true; - } + return true; +} - return false; +function hasUnhydratedTailNodes() { + return isHydrating && nextHydratableInstance !== null; } -/** - * Checks if an event is supported in the current execution environment. - * - * NOTE: This will not work correctly for non-generic events such as `change`, - * `reset`, `load`, `error`, and `select`. - * - * Borrows from Modernizr. - * - * @param {string} eventNameSuffix Event name, e.g. "click". - * @return {boolean} True if the event is supported. - * @internal - * @license Modernizr 3.0.0pre (Custom Build) | MIT - */ +function warnIfUnhydratedTailNodes(fiber) { + var nextInstance = nextHydratableInstance; -function isEventSupported(eventNameSuffix) { - if (!canUseDOM) { - return false; + while (nextInstance) { + warnUnhydratedInstance(fiber, nextInstance); + nextInstance = getNextHydratableSibling(nextInstance); } +} - var eventName = "on" + eventNameSuffix; - var isSupported = eventName in document; +function resetHydrationState() { + hydrationParentFiber = null; + nextHydratableInstance = null; + isHydrating = false; + didSuspendOrErrorDEV = false; +} - if (!isSupported) { - var element = document.createElement("div"); - element.setAttribute(eventName, "return;"); - isSupported = typeof element[eventName] === "function"; +function upgradeHydrationErrorsToRecoverable() { + if (hydrationErrors !== null) { + // Successfully completed a forced client render. The errors that occurred + // during the hydration attempt are now recovered. We will log them in + // commit phase, once the entire tree has finished. + queueRecoverableErrors(hydrationErrors); + hydrationErrors = null; } - - return isSupported; } -function registerEvents$2() { - registerTwoPhaseEvent("onChange", [ - "change", - "click", - "focusin", - "focusout", - "input", - "keydown", - "keyup", - "selectionchange" - ]); +function getIsHydrating() { + return isHydrating; } -function createAndAccumulateChangeEvent( - dispatchQueue, - inst, - nativeEvent, - target -) { - // Flag this event loop as needing state restore. - enqueueStateRestore(target); - var listeners = accumulateTwoPhaseListeners(inst, "onChange"); - - if (listeners.length > 0) { - var event = new SyntheticEvent( - "onChange", - "change", - null, - nativeEvent, - target - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); +function queueHydrationError(error) { + if (hydrationErrors === null) { + hydrationErrors = [error]; + } else { + hydrationErrors.push(error); } } -/** - * For IE shims - */ -var activeElement$1 = null; -var activeElementInst$1 = null; -/** - * SECTION: handle `change` event - */ +// we wait until the current render is over (either finished or interrupted) +// before adding it to the fiber/hook queue. Push to this array so we can +// access the queue, fiber, update, et al later. -function shouldUseChangeEvent(elem) { - var nodeName = elem.nodeName && elem.nodeName.toLowerCase(); - return ( - nodeName === "select" || (nodeName === "input" && elem.type === "file") - ); -} +var concurrentQueues = []; +var concurrentQueuesIndex = 0; +var concurrentlyUpdatedLanes = NoLanes; +function finishQueueingConcurrentUpdates() { + var endIndex = concurrentQueuesIndex; + concurrentQueuesIndex = 0; + concurrentlyUpdatedLanes = NoLanes; + var i = 0; -function manualDispatchChangeEvent(nativeEvent) { - var dispatchQueue = []; - createAndAccumulateChangeEvent( - dispatchQueue, - activeElementInst$1, - nativeEvent, - getEventTarget(nativeEvent) - ); // If change and propertychange bubbled, we'd just bind to it like all the - // other events and have it go through ReactBrowserEventEmitter. Since it - // doesn't, we manually listen for the events and so we have to enqueue and - // process the abstract event manually. - // - // Batching is necessary here in order to ensure that all event handlers run - // before the next rerender (including event handlers attached to ancestor - // elements instead of directly on the input). Without this, controlled - // components don't work properly in conjunction with event bubbling because - // the component is rerendered and the value reverted before all the event - // handlers can run. See https://github.com/facebook/react/issues/708. + while (i < endIndex) { + var fiber = concurrentQueues[i]; + concurrentQueues[i++] = null; + var queue = concurrentQueues[i]; + concurrentQueues[i++] = null; + var update = concurrentQueues[i]; + concurrentQueues[i++] = null; + var lane = concurrentQueues[i]; + concurrentQueues[i++] = null; - batchedUpdates$1(runEventInBatch, dispatchQueue); -} + if (queue !== null && update !== null) { + var pending = queue.pending; -function runEventInBatch(dispatchQueue) { - processDispatchQueue(dispatchQueue, 0); -} + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } -function getInstIfValueChanged(targetInst) { - var targetNode = getNodeFromInstance(targetInst); + queue.pending = update; + } - if (updateValueIfChanged(targetNode)) { - return targetInst; + if (lane !== NoLane) { + markUpdateLaneFromFiberToRoot(fiber, update, lane); + } } } - -function getTargetInstForChangeEvent(domEventName, targetInst) { - if (domEventName === "change") { - return targetInst; - } +function getConcurrentlyUpdatedLanes() { + return concurrentlyUpdatedLanes; } -/** - * SECTION: handle `input` event - */ -var isInputEventSupported = false; +function enqueueUpdate$1(fiber, queue, update, lane) { + // Don't update the `childLanes` on the return path yet. If we already in + // the middle of rendering, wait until after it has completed. + concurrentQueues[concurrentQueuesIndex++] = fiber; + concurrentQueues[concurrentQueuesIndex++] = queue; + concurrentQueues[concurrentQueuesIndex++] = update; + concurrentQueues[concurrentQueuesIndex++] = lane; + concurrentlyUpdatedLanes = mergeLanes(concurrentlyUpdatedLanes, lane); // The fiber's `lane` field is used in some places to check if any work is + // scheduled, to perform an eager bailout, so we need to update it immediately. + // TODO: We should probably move this to the "shared" queue instead. -if (canUseDOM) { - // IE9 claims to support the input event but fails to trigger it when - // deleting text, so we ignore its input events. - isInputEventSupported = - isEventSupported("input") && - (!document.documentMode || document.documentMode > 9); + fiber.lanes = mergeLanes(fiber.lanes, lane); + var alternate = fiber.alternate; + + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } } -/** - * (For IE <=9) Starts tracking propertychange events on the passed-in element - * and override the value property so that we can distinguish user events from - * value changes in JS. - */ -function startWatchingForValueChange(target, targetInst) { - activeElement$1 = target; - activeElementInst$1 = targetInst; - activeElement$1.attachEvent("onpropertychange", handlePropertyChange); +function enqueueConcurrentHookUpdate(fiber, queue, update, lane) { + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); + return getRootForUpdatedFiber(fiber); } -/** - * (For IE <=9) Removes the event listeners from the currently-tracked element, - * if any exists. - */ +function enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update) { + // This function is used to queue an update that doesn't need a rerender. The + // only reason we queue it is in case there's a subsequent higher priority + // update that causes it to be rebased. + var lane = NoLane; + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); // Usually we can rely on the upcoming render phase to process the concurrent + // queue. However, since this is a bail out, we're not scheduling any work + // here. So the update we just queued will leak until something else happens + // to schedule work (if ever). + // + // Check if we're currently in the middle of rendering a tree, and if not, + // process the queue immediately to prevent a leak. -function stopWatchingForValueChange() { - if (!activeElement$1) { - return; + var isConcurrentlyRendering = getWorkInProgressRoot() !== null; + + if (!isConcurrentlyRendering) { + finishQueueingConcurrentUpdates(); } +} +function enqueueConcurrentClassUpdate(fiber, queue, update, lane) { + var concurrentQueue = queue; + var concurrentUpdate = update; + enqueueUpdate$1(fiber, concurrentQueue, concurrentUpdate, lane); + return getRootForUpdatedFiber(fiber); +} +function enqueueConcurrentRenderForLane(fiber, lane) { + enqueueUpdate$1(fiber, null, null, lane); + return getRootForUpdatedFiber(fiber); +} // Calling this function outside this module should only be done for backwards +// compatibility and should always be accompanied by a warning. - activeElement$1.detachEvent("onpropertychange", handlePropertyChange); - activeElement$1 = null; - activeElementInst$1 = null; +function unsafe_markUpdateLaneFromFiberToRoot(sourceFiber, lane) { + // NOTE: For Hyrum's Law reasons, if an infinite update loop is detected, it + // should throw before `markUpdateLaneFromFiberToRoot` is called. But this is + // undefined behavior and we can change it if we need to; it just so happens + // that, at the time of this writing, there's an internal product test that + // happens to rely on this. + var root = getRootForUpdatedFiber(sourceFiber); + markUpdateLaneFromFiberToRoot(sourceFiber, null, lane); + return root; } -/** - * (For IE <=9) Handles a propertychange event, sending a `change` event if - * the value of the active element has changed. - */ -// $FlowFixMe[missing-local-annot] -function handlePropertyChange(nativeEvent) { - if (nativeEvent.propertyName !== "value") { - return; - } +function markUpdateLaneFromFiberToRoot(sourceFiber, update, lane) { + // Update the source fiber's lanes + sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane); + var alternate = sourceFiber.alternate; - if (getInstIfValueChanged(activeElementInst$1)) { - manualDispatchChangeEvent(nativeEvent); - } -} + if (alternate !== null) { + alternate.lanes = mergeLanes(alternate.lanes, lane); + } // Walk the parent path to the root and update the child lanes. -function handleEventsForInputEventPolyfill(domEventName, target, targetInst) { - if (domEventName === "focusin") { - // In IE9, propertychange fires for most input events but is buggy and - // doesn't fire when text is deleted, but conveniently, selectionchange - // appears to fire in all of the remaining cases so we catch those and - // forward the event if the value has changed - // In either case, we don't want to call the event handler if the value - // is changed from JS so we redefine a setter for `.value` that updates - // our activeElementValue variable, allowing us to ignore those changes - // - // stopWatching() should be a noop here but we call it just in case we - // missed a blur event somehow. - stopWatchingForValueChange(); - startWatchingForValueChange(target, targetInst); - } else if (domEventName === "focusout") { - stopWatchingForValueChange(); - } -} // For IE8 and IE9. + var isHidden = false; + var parent = sourceFiber.return; + var node = sourceFiber; -function getTargetInstForInputEventPolyfill(domEventName, targetInst) { - if ( - domEventName === "selectionchange" || - domEventName === "keyup" || - domEventName === "keydown" - ) { - // On the selectionchange event, the target is just document which isn't - // helpful for us so just check activeElement instead. - // - // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire - // propertychange on the first input event after setting `value` from a - // script and fires only keydown, keypress, keyup. Catching keyup usually - // gets it and catching keydown lets us fire an event for the first - // keystroke if user does a key repeat (it'll be a little delayed: right - // before the second keystroke). Other input methods (e.g., paste) seem to - // fire selectionchange normally. - return getInstIfValueChanged(activeElementInst$1); - } -} -/** - * SECTION: handle `click` event - */ + while (parent !== null) { + parent.childLanes = mergeLanes(parent.childLanes, lane); + alternate = parent.alternate; -function shouldUseClickEvent(elem) { - // Use the `click` event to detect changes to checkbox and radio inputs. - // This approach works across all browsers, whereas `change` does not fire - // until `blur` in IE8. - var nodeName = elem.nodeName; - return ( - nodeName && - nodeName.toLowerCase() === "input" && - (elem.type === "checkbox" || elem.type === "radio") - ); -} + if (alternate !== null) { + alternate.childLanes = mergeLanes(alternate.childLanes, lane); + } -function getTargetInstForClickEvent(domEventName, targetInst) { - if (domEventName === "click") { - return getInstIfValueChanged(targetInst); + if (parent.tag === OffscreenComponent) { + // Check if this offscreen boundary is currently hidden. + // + // The instance may be null if the Offscreen parent was unmounted. Usually + // the parent wouldn't be reachable in that case because we disconnect + // fibers from the tree when they are deleted. However, there's a weird + // edge case where setState is called on a fiber that was interrupted + // before it ever mounted. Because it never mounts, it also never gets + // deleted. Because it never gets deleted, its return pointer never gets + // disconnected. Which means it may be attached to a deleted Offscreen + // parent node. (This discovery suggests it may be better for memory usage + // if we don't attach the `return` pointer until the commit phase, though + // in order to do that we'd need some other way to track the return + // pointer during the initial render, like on the stack.) + // + // This case is always accompanied by a warning, but we still need to + // account for it. (There may be other cases that we haven't discovered, + // too.) + var offscreenInstance = parent.stateNode; + + if ( + offscreenInstance !== null && + !(offscreenInstance._visibility & OffscreenVisible) + ) { + isHidden = true; + } + } + + node = parent; + parent = parent.return; } -} -function getTargetInstForInputOrChangeEvent(domEventName, targetInst) { - if (domEventName === "input" || domEventName === "change") { - return getInstIfValueChanged(targetInst); + if (isHidden && update !== null && node.tag === HostRoot) { + var root = node.stateNode; + markHiddenUpdate(root, update, lane); } } -function handleControlledInputBlur(node) { - var state = node._wrapperState; +function getRootForUpdatedFiber(sourceFiber) { + // TODO: We will detect and infinite update loop and throw even if this fiber + // has already unmounted. This isn't really necessary but it happens to be the + // current behavior we've used for several release cycles. Consider not + // performing this check if the updated fiber already unmounted, since it's + // not possible for that to cause an infinite update loop. + throwIfInfiniteUpdateLoopDetected(); // When a setState happens, we must ensure the root is scheduled. Because + // update queues do not have a backpointer to the root, the only way to do + // this currently is to walk up the return path. This used to not be a big + // deal because we would have to walk up the return path to set + // the `childLanes`, anyway, but now those two traversals happen at + // different times. + // TODO: Consider adding a `root` backpointer on the update queue. - if (!state || !state.controlled || node.type !== "number") { - return; - } + detectUpdateOnUnmountedFiber(sourceFiber, sourceFiber); + var node = sourceFiber; + var parent = node.return; - if (!disableInputAttributeSyncing) { - // If controlled, assign the value attribute to the current value on blur - setDefaultValue(node, "number", node.value); + while (parent !== null) { + detectUpdateOnUnmountedFiber(sourceFiber, node); + node = parent; + parent = node.return; } + + return node.tag === HostRoot ? node.stateNode : null; } -/** - * This plugin creates an `onChange` event that normalizes change events - * across form elements. This event fires at a time when it's possible to - * change the element's value without seeing a flicker. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - select - */ -function extractEvents$4( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var targetNode = targetInst ? getNodeFromInstance(targetInst) : window; - var getTargetInstFunc, handleEventFunc; +function detectUpdateOnUnmountedFiber(sourceFiber, parent) { + { + var alternate = parent.alternate; - if (shouldUseChangeEvent(targetNode)) { - getTargetInstFunc = getTargetInstForChangeEvent; - } else if (isTextInputElement(targetNode)) { - if (isInputEventSupported) { - getTargetInstFunc = getTargetInstForInputOrChangeEvent; - } else { - getTargetInstFunc = getTargetInstForInputEventPolyfill; - handleEventFunc = handleEventsForInputEventPolyfill; + if ( + alternate === null && + (parent.flags & (Placement | Hydrating)) !== NoFlags$1 + ) { + warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber); } - } else if (shouldUseClickEvent(targetNode)) { - getTargetInstFunc = getTargetInstForClickEvent; - } else if ( - enableCustomElementPropertySupport && - targetInst && - isCustomComponent(targetInst.elementType, targetInst.memoizedProps) - ) { - getTargetInstFunc = getTargetInstForChangeEvent; } +} - if (getTargetInstFunc) { - var inst = getTargetInstFunc(domEventName, targetInst); - - if (inst) { - createAndAccumulateChangeEvent( - dispatchQueue, - inst, - nativeEvent, - nativeEventTarget - ); - return; - } - } +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`. - if (handleEventFunc) { - handleEventFunc(domEventName, targetNode, targetInst); - } // When blurring, set the value attribute for number inputs +var hasForceUpdate = false; +var didWarnUpdateInsideUpdate; +var currentlyProcessingQueue; - if (domEventName === "focusout") { - handleControlledInputBlur(targetNode); - } +{ + didWarnUpdateInsideUpdate = false; + currentlyProcessingQueue = null; } -function registerEvents$1() { - registerDirectEvent("onMouseEnter", ["mouseout", "mouseover"]); - registerDirectEvent("onMouseLeave", ["mouseout", "mouseover"]); - registerDirectEvent("onPointerEnter", ["pointerout", "pointerover"]); - registerDirectEvent("onPointerLeave", ["pointerout", "pointerover"]); +function initializeUpdateQueue(fiber) { + var queue = { + baseState: fiber.memoizedState, + firstBaseUpdate: null, + lastBaseUpdate: null, + shared: { + pending: null, + lanes: NoLanes, + hiddenCallbacks: null + }, + callbacks: null + }; + fiber.updateQueue = queue; } -/** - * For almost every interaction we care about, there will be both a top-level - * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that - * we do not extract duplicate events. However, moving the mouse into the - * browser from outside will not fire a `mouseout` event. In this case, we use - * the `mouseover` top-level event. - */ - -function extractEvents$3( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var isOverEvent = - domEventName === "mouseover" || domEventName === "pointerover"; - var isOutEvent = domEventName === "mouseout" || domEventName === "pointerout"; - - if (isOverEvent && !isReplayingEvent(nativeEvent)) { - // If this is an over event with a target, we might have already dispatched - // the event in the out event of the other target. If this is replayed, - // then it's because we couldn't dispatch against this target previously - // so we have to do it now instead. - var related = nativeEvent.relatedTarget || nativeEvent.fromElement; +function cloneUpdateQueue(current, workInProgress) { + // Clone the update queue from current. Unless it's already a clone. + var queue = workInProgress.updateQueue; + var currentQueue = current.updateQueue; - if (related) { - // If the related node is managed by React, we can assume that we have - // already dispatched the corresponding events during its mouseout. - if ( - getClosestInstanceFromNode(related) || - isContainerMarkedAsRoot(related) - ) { - return; - } - } + if (queue === currentQueue) { + var clone = { + baseState: currentQueue.baseState, + firstBaseUpdate: currentQueue.firstBaseUpdate, + lastBaseUpdate: currentQueue.lastBaseUpdate, + shared: currentQueue.shared, + callbacks: null + }; + workInProgress.updateQueue = clone; } +} +function createUpdate(lane) { + var update = { + lane: lane, + tag: UpdateState, + payload: null, + callback: null, + next: null + }; + return update; +} +function enqueueUpdate(fiber, update, lane) { + var updateQueue = fiber.updateQueue; - if (!isOutEvent && !isOverEvent) { - // Must not be a mouse or pointer in or out - ignoring. - return; + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. + return null; } - var win; // TODO: why is this nullable in the types but we read from it? + var sharedQueue = updateQueue.shared; - if (nativeEventTarget.window === nativeEventTarget) { - // `nativeEventTarget` is probably a window object. - win = nativeEventTarget; - } else { - // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. - var doc = nativeEventTarget.ownerDocument; + { + if ( + currentlyProcessingQueue === sharedQueue && + !didWarnUpdateInsideUpdate + ) { + var componentName = getComponentNameFromFiber(fiber); - if (doc) { - win = doc.defaultView || doc.parentWindow; - } else { - win = window; + error( + "An update (setState, replaceState, or forceUpdate) was scheduled " + + "from inside an update function. Update functions should be pure, " + + "with zero side-effects. Consider using componentDidUpdate or a " + + "callback.\n\nPlease update the following component: %s", + componentName + ); + + didWarnUpdateInsideUpdate = true; } } - var from; - var to; - - if (isOutEvent) { - var _related = nativeEvent.relatedTarget || nativeEvent.toElement; + if (isUnsafeClassRenderPhaseUpdate(fiber)) { + // This is an unsafe render phase update. Add directly to the update + // queue so we can process it immediately during the current render. + var pending = sharedQueue.pending; - from = targetInst; - to = _related ? getClosestInstanceFromNode(_related) : null; + if (pending === null) { + // This is the first update. Create a circular list. + update.next = update; + } else { + update.next = pending.next; + pending.next = update; + } - if (to !== null) { - var nearestMounted = getNearestMountedFiber(to); - var tag = to.tag; + sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering + // this fiber. This is for backwards compatibility in the case where you + // update a different component during render phase than the one that is + // currently renderings (a pattern that is accompanied by a warning). - if ( - to !== nearestMounted || - (tag !== HostComponent && tag !== HostSingleton && tag !== HostText) - ) { - to = null; - } - } + return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane); } else { - // Moving to a node from outside the window. - from = null; - to = targetInst; + return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane); } +} +function entangleTransitions(root, fiber, lane) { + var updateQueue = fiber.updateQueue; - if (from === to) { - // Nothing pertains to our managed components. + if (updateQueue === null) { + // Only occurs if the fiber has been unmounted. return; } - var SyntheticEventCtor = SyntheticMouseEvent; - var leaveEventType = "onMouseLeave"; - var enterEventType = "onMouseEnter"; - var eventTypePrefix = "mouse"; + var sharedQueue = updateQueue.shared; - if (domEventName === "pointerout" || domEventName === "pointerover") { - SyntheticEventCtor = SyntheticPointerEvent; - leaveEventType = "onPointerLeave"; - enterEventType = "onPointerEnter"; - eventTypePrefix = "pointer"; - } + if (isTransitionLane(lane)) { + var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must + // have finished. We can remove them from the shared queue, which represents + // a superset of the actually pending lanes. In some cases we may entangle + // more than we need to, but that's OK. In fact it's worse if we *don't* + // entangle when we should. - var fromNode = from == null ? win : getNodeFromInstance(from); - var toNode = to == null ? win : getNodeFromInstance(to); - var leave = new SyntheticEventCtor( - leaveEventType, - eventTypePrefix + "leave", - from, - nativeEvent, - nativeEventTarget - ); - leave.target = fromNode; - leave.relatedTarget = toNode; - var enter = null; // We should only process this nativeEvent if we are processing - // the first ancestor. Next time, we will ignore the event. + queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes. - var nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget); + var newQueueLanes = mergeLanes(queueLanes, lane); + sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if + // the lane finished since the last time we entangled it. So we need to + // entangle it again, just to be sure. - if (nativeTargetInst === targetInst) { - var enterEvent = new SyntheticEventCtor( - enterEventType, - eventTypePrefix + "enter", - to, - nativeEvent, - nativeEventTarget - ); - enterEvent.target = toNode; - enterEvent.relatedTarget = fromNode; - enter = enterEvent; + markRootEntangled(root, newQueueLanes); } - - accumulateEnterLeaveTwoPhaseListeners(dispatchQueue, leave, enter, from, to); } +function enqueueCapturedUpdate(workInProgress, capturedUpdate) { + // Captured updates are updates that are thrown by a child during the render + // phase. They should be discarded if the render is aborted. Therefore, + // we should only put them on the work-in-progress queue, not the current one. + var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone. -/** - * 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 current = workInProgress.alternate; -var objectIs = typeof Object.is === "function" ? Object.is : is; // $FlowFixMe[method-unbinding] + if (current !== null) { + var currentQueue = current.updateQueue; -/** - * 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. - */ + if (queue === currentQueue) { + // The work-in-progress queue is the same as current. This happens when + // we bail out on a parent fiber that then captures an error thrown by + // a child. Since we want to append the update only to the work-in + // -progress queue, we need to clone the updates. We usually clone during + // processUpdateQueue, but that didn't happen in this case because we + // skipped over the parent when we bailed out. + var newFirst = null; + var newLast = null; + var firstBaseUpdate = queue.firstBaseUpdate; -function shallowEqual(objA, objB) { - if (objectIs(objA, objB)) { - return true; - } + if (firstBaseUpdate !== null) { + // Loop through the updates and clone them. + var update = firstBaseUpdate; - if ( - typeof objA !== "object" || - objA === null || - typeof objB !== "object" || - objB === null - ) { - return false; - } + do { + var clone = { + lane: update.lane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; - var keysA = Object.keys(objA); - var keysB = Object.keys(objB); + if (newLast === null) { + newFirst = newLast = clone; + } else { + newLast.next = clone; + newLast = clone; + } // $FlowFixMe[incompatible-type] we bail out when we get a null - if (keysA.length !== keysB.length) { - return false; - } // Test for A's keys different from B. + update = update.next; + } while (update !== null); // Append the captured update the end of the cloned list. - for (var i = 0; i < keysA.length; i++) { - var currentKey = keysA[i]; + if (newLast === null) { + newFirst = newLast = capturedUpdate; + } else { + newLast.next = capturedUpdate; + newLast = capturedUpdate; + } + } else { + // There are no base updates. + newFirst = newLast = capturedUpdate; + } - if ( - !hasOwnProperty.call(objB, currentKey) || - !objectIs(objA[currentKey], objB[currentKey]) - ) { - return false; + queue = { + baseState: currentQueue.baseState, + firstBaseUpdate: newFirst, + lastBaseUpdate: newLast, + shared: currentQueue.shared, + callbacks: currentQueue.callbacks + }; + workInProgress.updateQueue = queue; + return; } - } - - return true; -} + } // Append the update to the end of the list. -/** - * Given any node return the first leaf node without children. - * - * @param {DOMElement|DOMTextNode} node - * @return {DOMElement|DOMTextNode} - */ + var lastBaseUpdate = queue.lastBaseUpdate; -function getLeafNode(node) { - while (node && node.firstChild) { - node = node.firstChild; + if (lastBaseUpdate === null) { + queue.firstBaseUpdate = capturedUpdate; + } else { + lastBaseUpdate.next = capturedUpdate; } - return node; -} -/** - * Get the next sibling within a container. This will walk up the - * DOM if a node's siblings have been exhausted. - * - * @param {DOMElement|DOMTextNode} node - * @return {?DOMElement|DOMTextNode} - */ - -function getSiblingNode(node) { - while (node) { - if (node.nextSibling) { - return node.nextSibling; - } - - node = node.parentNode; - } + queue.lastBaseUpdate = capturedUpdate; } -/** - * Get object describing the nodes which contain characters at offset. - * - * @param {DOMElement|DOMTextNode} root - * @param {number} offset - * @return {?object} - */ - -function getNodeForCharacterOffset(root, offset) { - var node = getLeafNode(root); - var nodeStart = 0; - var nodeEnd = 0; - while (node) { - if (node.nodeType === TEXT_NODE) { - nodeEnd = nodeStart + node.textContent.length; +function getStateFromUpdate( + workInProgress, + queue, + update, + prevState, + nextProps, + instance +) { + switch (update.tag) { + case ReplaceState: { + var payload = update.payload; - if (nodeStart <= offset && nodeEnd >= offset) { - return { - node: node, - offset: offset - nodeStart - }; - } + if (typeof payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - nodeStart = nodeEnd; - } + var nextState = payload.call(instance, prevState, nextProps); - node = getLeafNode(getSiblingNode(node)); - } -} + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); -/** - * @param {DOMElement} outerNode - * @return {?object} - */ + try { + payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } -function getOffsets(outerNode) { - var ownerDocument = outerNode.ownerDocument; - var win = (ownerDocument && ownerDocument.defaultView) || window; - var selection = win.getSelection && win.getSelection(); + exitDisallowedContextReadInDEV(); + } - if (!selection || selection.rangeCount === 0) { - return null; - } + return nextState; + } // State object - var anchorNode = selection.anchorNode, - anchorOffset = selection.anchorOffset, - focusNode = selection.focusNode, - focusOffset = selection.focusOffset; // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the - // up/down buttons on an . Anonymous divs do not seem to - // expose properties, triggering a "Permission denied error" if any of its - // properties are accessed. The only seemingly possible way to avoid erroring - // is to access a property that typically works for non-anonymous divs and - // catch any error that may otherwise arise. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=208427 + return payload; + } - try { - /* eslint-disable ft-flow/no-unused-expressions */ - anchorNode.nodeType; - focusNode.nodeType; - /* eslint-enable ft-flow/no-unused-expressions */ - } catch (e) { - return null; - } + case CaptureUpdate: { + workInProgress.flags = + (workInProgress.flags & ~ShouldCapture) | DidCapture; + } + // Intentional fallthrough - return getModernOffsetsFromPoints( - outerNode, - anchorNode, - anchorOffset, - focusNode, - focusOffset - ); -} -/** - * Returns {start, end} where `start` is the character/codepoint index of - * (anchorNode, anchorOffset) within the textContent of `outerNode`, and - * `end` is the index of (focusNode, focusOffset). - * - * Returns null if you pass in garbage input but we should probably just crash. - * - * Exported only for testing. - */ + case UpdateState: { + var _payload = update.payload; + var partialState; -function getModernOffsetsFromPoints( - outerNode, - anchorNode, - anchorOffset, - focusNode, - focusOffset -) { - var length = 0; - var start = -1; - var end = -1; - var indexWithinAnchor = 0; - var indexWithinFocus = 0; - var node = outerNode; - var parentNode = null; + if (typeof _payload === "function") { + // Updater function + { + enterDisallowedContextReadInDEV(); + } - outer: while (true) { - var next = null; + partialState = _payload.call(instance, prevState, nextProps); - while (true) { - if ( - node === anchorNode && - (anchorOffset === 0 || node.nodeType === TEXT_NODE) - ) { - start = length + anchorOffset; - } + { + if (workInProgress.mode & StrictLegacyMode) { + setIsStrictModeForDevtools(true); - if ( - node === focusNode && - (focusOffset === 0 || node.nodeType === TEXT_NODE) - ) { - end = length + focusOffset; - } + try { + _payload.call(instance, prevState, nextProps); + } finally { + setIsStrictModeForDevtools(false); + } + } - if (node.nodeType === TEXT_NODE) { - length += node.nodeValue.length; + exitDisallowedContextReadInDEV(); + } + } else { + // Partial state object + partialState = _payload; } - if ((next = node.firstChild) === null) { - break; - } // Moving from `node` to its first child `next`. + if (partialState === null || partialState === undefined) { + // Null and undefined are treated as no-ops. + return prevState; + } // Merge the partial state and the previous state. - parentNode = node; - node = next; + return assign({}, prevState, partialState); } - while (true) { - if (node === outerNode) { - // If `outerNode` has children, this is always the second time visiting - // it. If it has no children, this is still the first loop, and the only - // valid selection is anchorNode and focusNode both equal to this node - // and both offsets 0, in which case we will have handled above. - break outer; - } - - if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) { - start = length; - } - - if (parentNode === focusNode && ++indexWithinFocus === focusOffset) { - end = length; - } - - if ((next = node.nextSibling) !== null) { - break; - } - - node = parentNode; - parentNode = node.parentNode; - } // Moving from `node` to its next sibling `next`. - - node = next; - } - - if (start === -1 || end === -1) { - // This should never happen. (Would happen if the anchor/focus nodes aren't - // actually inside the passed-in node.) - return null; + case ForceUpdate: { + hasForceUpdate = true; + return prevState; + } } - return { - start: start, - end: end - }; + return prevState; } -/** - * In modern non-IE browsers, we can support both forward and backward - * selections. - * - * Note: IE10+ supports the Selection object, but it does not support - * the `extend` method, which means that even in modern IE, it's not possible - * to programmatically create a backward selection. Thus, for all IE - * versions, we use the old IE API to create our selections. - * - * @param {DOMElement|DOMTextNode} node - * @param {object} offsets - */ -function setOffsets(node, offsets) { - var doc = node.ownerDocument || document; - var win = (doc && doc.defaultView) || window; // Edge fails with "Object expected" in some scenarios. - // (For instance: TinyMCE editor used in a list component that supports pasting to add more, - // fails when pasting 100+ items) +function processUpdateQueue(workInProgress, props, instance, renderLanes) { + // This is always non-null on a ClassComponent or HostRoot + var queue = workInProgress.updateQueue; + hasForceUpdate = false; - if (!win.getSelection) { - return; + { + currentlyProcessingQueue = queue.shared; } - var selection = win.getSelection(); - var length = node.textContent.length; - var start = Math.min(offsets.start, length); - var end = offsets.end === undefined ? start : Math.min(offsets.end, length); // IE 11 uses modern selection, but doesn't support the extend method. - // Flip backward selections, so we can set with a single range. - - if (!selection.extend && start > end) { - var temp = end; - end = start; - start = temp; - } + var firstBaseUpdate = queue.firstBaseUpdate; + var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue. - var startMarker = getNodeForCharacterOffset(node, start); - var endMarker = getNodeForCharacterOffset(node, end); + var pendingQueue = queue.shared.pending; - if (startMarker && endMarker) { - if ( - selection.rangeCount === 1 && - selection.anchorNode === startMarker.node && - selection.anchorOffset === startMarker.offset && - selection.focusNode === endMarker.node && - selection.focusOffset === endMarker.offset - ) { - return; - } + if (pendingQueue !== null) { + queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first + // and last so that it's non-circular. - var range = doc.createRange(); - range.setStart(startMarker.node, startMarker.offset); - selection.removeAllRanges(); + var lastPendingUpdate = pendingQueue; + var firstPendingUpdate = lastPendingUpdate.next; + lastPendingUpdate.next = null; // Append pending updates to base queue - if (start > end) { - selection.addRange(range); - selection.extend(endMarker.node, endMarker.offset); + if (lastBaseUpdate === null) { + firstBaseUpdate = firstPendingUpdate; } else { - range.setEnd(endMarker.node, endMarker.offset); - selection.addRange(range); + lastBaseUpdate.next = firstPendingUpdate; } - } -} - -function isTextNode(node) { - return node && node.nodeType === TEXT_NODE; -} -function containsNode$1(outerNode, innerNode) { - if (!outerNode || !innerNode) { - return false; - } else if (outerNode === innerNode) { - return true; - } else if (isTextNode(outerNode)) { - return false; - } else if (isTextNode(innerNode)) { - return containsNode$1(outerNode, innerNode.parentNode); - } else if ("contains" in outerNode) { - return outerNode.contains(innerNode); - } else if (outerNode.compareDocumentPosition) { - return !!(outerNode.compareDocumentPosition(innerNode) & 16); - } else { - return false; - } -} + lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then + // we need to transfer the updates to that queue, too. Because the base + // queue is a singly-linked list with no cycles, we can append to both + // lists and take advantage of structural sharing. + // TODO: Pass `current` as argument -function isInDocument(node) { - return ( - node && - node.ownerDocument && - containsNode$1(node.ownerDocument.documentElement, node) - ); -} + var current = workInProgress.alternate; -function isSameOriginFrame(iframe) { - try { - // Accessing the contentDocument of a HTMLIframeElement can cause the browser - // to throw, e.g. if it has a cross-origin src attribute. - // Safari will show an error in the console when the access results in "Blocked a frame with origin". e.g: - // iframe.contentDocument.defaultView; - // A safety way is to access one of the cross origin properties: Window or Location - // Which might result in "SecurityError" DOM Exception and it is compatible to Safari. - // https://html.spec.whatwg.org/multipage/browsers.html#integration-with-idl - return typeof iframe.contentWindow.location.href === "string"; - } catch (err) { - return false; - } -} + if (current !== null) { + // This is always non-null on a ClassComponent or HostRoot + var currentQueue = current.updateQueue; + var currentLastBaseUpdate = currentQueue.lastBaseUpdate; -function getActiveElementDeep() { - var win = window; - var element = getActiveElement(); + if (currentLastBaseUpdate !== lastBaseUpdate) { + if (currentLastBaseUpdate === null) { + currentQueue.firstBaseUpdate = firstPendingUpdate; + } else { + currentLastBaseUpdate.next = firstPendingUpdate; + } - while (element instanceof win.HTMLIFrameElement) { - if (isSameOriginFrame(element)) { - win = element.contentWindow; - } else { - return element; + currentQueue.lastBaseUpdate = lastPendingUpdate; + } } + } // These values may change as we process the queue. - element = getActiveElement(win.document); - } + if (firstBaseUpdate !== null) { + // Iterate through the list of updates to compute the result. + var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes + // from the original lanes. - return element; -} -/** - * @ReactInputSelection: React input selection module. Based on Selection.js, - * but modified to be suitable for react and has a couple of bug fixes (doesn't - * assume buttons have range selections allowed). - * Input selection module for React. - */ + var newLanes = NoLanes; + var newBaseState = null; + var newFirstBaseUpdate = null; + var newLastBaseUpdate = null; + var update = firstBaseUpdate; -/** - * @hasSelectionCapabilities: we get the element types that support selection - * from https://html.spec.whatwg.org/#do-not-apply, looking at `selectionStart` - * and `selectionEnd` rows. - */ + do { + // An extra OffscreenLane bit is added to updates that were made to + // a hidden tree, so that we can distinguish them from updates that were + // already there when the tree was hidden. + var updateLane = removeLanes(update.lane, OffscreenLane); + var isHiddenUpdate = updateLane !== update.lane; // Check if this update was made while the tree was hidden. If so, then + // it's not a "base" update and we should disregard the extra base lanes + // that were added to renderLanes when we entered the Offscreen tree. -function hasSelectionCapabilities(elem) { - var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase(); - return ( - nodeName && - ((nodeName === "input" && - (elem.type === "text" || - elem.type === "search" || - elem.type === "tel" || - elem.type === "url" || - elem.type === "password")) || - nodeName === "textarea" || - elem.contentEditable === "true") - ); -} -function getSelectionInformation() { - var focusedElem = getActiveElementDeep(); - return { - focusedElem: focusedElem, - selectionRange: hasSelectionCapabilities(focusedElem) - ? getSelection$1(focusedElem) - : null - }; -} -/** - * @restoreSelection: If any selection information was potentially lost, - * restore it. This is useful when performing operations that could remove dom - * nodes and place them back in, resulting in focus being lost. - */ + var shouldSkipUpdate = isHiddenUpdate + ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane) + : !isSubsetOfLanes(renderLanes, updateLane); -function restoreSelection(priorSelectionInformation) { - var curFocusedElem = getActiveElementDeep(); - var priorFocusedElem = priorSelectionInformation.focusedElem; - var priorSelectionRange = priorSelectionInformation.selectionRange; + if (shouldSkipUpdate) { + // Priority is insufficient. Skip this update. If this is the first + // skipped update, the previous update/state is the new base + // update/state. + var clone = { + lane: updateLane, + tag: update.tag, + payload: update.payload, + callback: update.callback, + next: null + }; - if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) { - if ( - priorSelectionRange !== null && - hasSelectionCapabilities(priorFocusedElem) - ) { - setSelection(priorFocusedElem, priorSelectionRange); - } // Focusing a node can change the scroll position, which is undesirable + if (newLastBaseUpdate === null) { + newFirstBaseUpdate = newLastBaseUpdate = clone; + newBaseState = newState; + } else { + newLastBaseUpdate = newLastBaseUpdate.next = clone; + } // Update the remaining priority in the queue. - var ancestors = []; - var ancestor = priorFocusedElem; + newLanes = mergeLanes(newLanes, updateLane); + } else { + // This update does have sufficient priority. + if (newLastBaseUpdate !== null) { + var _clone = { + // This update is going to be committed so we never want uncommit + // it. Using NoLane works because 0 is a subset of all bitmasks, so + // this will never be skipped by the check above. + lane: NoLane, + tag: update.tag, + payload: update.payload, + // When this update is rebased, we should not fire its + // callback again. + callback: null, + next: null + }; + newLastBaseUpdate = newLastBaseUpdate.next = _clone; + } // Process this update. - while ((ancestor = ancestor.parentNode)) { - if (ancestor.nodeType === ELEMENT_NODE) { - ancestors.push({ - element: ancestor, - left: ancestor.scrollLeft, - top: ancestor.scrollTop - }); + newState = getStateFromUpdate( + workInProgress, + queue, + update, + newState, + props, + instance + ); + var callback = update.callback; + + if (callback !== null) { + workInProgress.flags |= Callback; + + if (isHiddenUpdate) { + workInProgress.flags |= Visibility; + } + + var callbacks = queue.callbacks; + + if (callbacks === null) { + queue.callbacks = [callback]; + } else { + callbacks.push(callback); + } + } + } // $FlowFixMe[incompatible-type] we bail out when we get a null + + update = update.next; + + if (update === null) { + pendingQueue = queue.shared.pending; + + if (pendingQueue === null) { + break; + } else { + // An update was scheduled from inside a reducer. Add the new + // pending updates to the end of the list and keep processing. + var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we + // unravel them when transferring them to the base queue. + + var _firstPendingUpdate = _lastPendingUpdate.next; + _lastPendingUpdate.next = null; + update = _firstPendingUpdate; + queue.lastBaseUpdate = _lastPendingUpdate; + queue.shared.pending = null; + } } - } + } while (true); - if (typeof priorFocusedElem.focus === "function") { - priorFocusedElem.focus(); + if (newLastBaseUpdate === null) { + newBaseState = newState; } - for (var i = 0; i < ancestors.length; i++) { - var info = ancestors[i]; - info.element.scrollLeft = info.left; - info.element.scrollTop = info.top; - } + queue.baseState = newBaseState; + queue.firstBaseUpdate = newFirstBaseUpdate; + queue.lastBaseUpdate = newLastBaseUpdate; + + if (firstBaseUpdate === null) { + // `queue.lanes` is used for entangling transitions. We can set it back to + // zero once the queue is empty. + queue.shared.lanes = NoLanes; + } // 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. + + markSkippedUpdateLanes(newLanes); + workInProgress.lanes = newLanes; + workInProgress.memoizedState = newState; } -} -/** - * @getSelection: Gets the selection bounds of a focused textarea, input or - * contentEditable node. - * -@input: Look up selection bounds of this input - * -@return {start: selectionStart, end: selectionEnd} - */ -function getSelection$1(input) { - var selection; + { + currentlyProcessingQueue = null; + } +} - if ("selectionStart" in input) { - // Modern browser with input or textarea. - selection = { - start: input.selectionStart, - end: input.selectionEnd - }; - } else { - // Content editable or old IE textarea. - selection = getOffsets(input); +function callCallback(callback, context) { + if (typeof callback !== "function") { + throw new Error( + "Invalid argument passed as callback. Expected a function. Instead " + + ("received: " + callback) + ); } - return ( - selection || { - start: 0, - end: 0 - } - ); + callback.call(context); } -/** - * @setSelection: Sets the selection bounds of a textarea or input and focuses - * the input. - * -@input Set selection bounds of this input or textarea - * -@offsets Object of same form that is returned from get* - */ -function setSelection(input, offsets) { - var start = offsets.start; - var end = offsets.end; +function resetHasForceUpdateBeforeProcessing() { + hasForceUpdate = false; +} +function checkHasForceUpdateAfterProcessing() { + return hasForceUpdate; +} +function deferHiddenCallbacks(updateQueue) { + // When an update finishes on a hidden component, its callback should not + // be fired until/unless the component is made visible again. Stash the + // callback on the shared queue object so it can be fired later. + var newHiddenCallbacks = updateQueue.callbacks; - if (end === undefined) { - end = start; - } + if (newHiddenCallbacks !== null) { + var existingHiddenCallbacks = updateQueue.shared.hiddenCallbacks; - if ("selectionStart" in input) { - input.selectionStart = start; - input.selectionEnd = Math.min(end, input.value.length); - } else { - setOffsets(input, offsets); + if (existingHiddenCallbacks === null) { + updateQueue.shared.hiddenCallbacks = newHiddenCallbacks; + } else { + updateQueue.shared.hiddenCallbacks = + existingHiddenCallbacks.concat(newHiddenCallbacks); + } } } +function commitHiddenCallbacks(updateQueue, context) { + // This component is switching from hidden -> visible. Commit any callbacks + // that were previously deferred. + var hiddenCallbacks = updateQueue.shared.hiddenCallbacks; -var skipSelectionChangeEvent = - canUseDOM && "documentMode" in document && document.documentMode <= 11; + if (hiddenCallbacks !== null) { + updateQueue.shared.hiddenCallbacks = null; -function registerEvents() { - registerTwoPhaseEvent("onSelect", [ - "focusout", - "contextmenu", - "dragend", - "focusin", - "keydown", - "keyup", - "mousedown", - "mouseup", - "selectionchange" - ]); + for (var i = 0; i < hiddenCallbacks.length; i++) { + var callback = hiddenCallbacks[i]; + callCallback(callback, context); + } + } } +function commitCallbacks(updateQueue, context) { + var callbacks = updateQueue.callbacks; -var activeElement = null; -var activeElementInst = null; -var lastSelection = null; -var mouseDown = false; -/** - * Get an object which is a unique representation of the current selection. - * - * The return value will not be consistent across nodes or browsers, but - * two identical selections on the same node will return identical objects. - */ + if (callbacks !== null) { + updateQueue.callbacks = null; -function getSelection(node) { - if ("selectionStart" in node && hasSelectionCapabilities(node)) { - return { - start: node.selectionStart, - end: node.selectionEnd - }; - } else { - var win = (node.ownerDocument && node.ownerDocument.defaultView) || window; - var selection = win.getSelection(); - return { - anchorNode: selection.anchorNode, - anchorOffset: selection.anchorOffset, - focusNode: selection.focusNode, - focusOffset: selection.focusOffset - }; + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; + callCallback(callback, context); + } } } -/** - * Get document associated with the event target. - */ -function getEventTargetDocument(eventTarget) { - return eventTarget.window === eventTarget - ? eventTarget.document - : eventTarget.nodeType === DOCUMENT_NODE - ? eventTarget - : eventTarget.ownerDocument; -} /** - * Poll selection to see whether it's changed. - * - * @param {object} nativeEvent - * @param {object} nativeEventTarget - * @return {?SyntheticEvent} + * 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 constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) { - // Ensure we have the right element, and that the user is not dragging a - // selection (this matches native `select` event behavior). In HTML5, select - // fires only on input and textarea thus if there's no focused element we - // won't dispatch. - var doc = getEventTargetDocument(nativeEventTarget); +function shallowEqual(objA, objB) { + if (objectIs(objA, objB)) { + return true; + } if ( - mouseDown || - activeElement == null || - activeElement !== getActiveElement(doc) + typeof objA !== "object" || + objA === null || + typeof objB !== "object" || + objB === null ) { - return; - } // Only fire when selection has actually changed. + return false; + } - var currentSelection = getSelection(activeElement); + var keysA = Object.keys(objA); + var keysB = Object.keys(objB); - if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) { - lastSelection = currentSelection; - var listeners = accumulateTwoPhaseListeners(activeElementInst, "onSelect"); + if (keysA.length !== keysB.length) { + return false; + } // Test for A's keys different from B. - if (listeners.length > 0) { - var event = new SyntheticEvent( - "onSelect", - "select", - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); - event.target = activeElement; + for (var i = 0; i < keysA.length; i++) { + var currentKey = keysA[i]; + + if ( + !hasOwnProperty.call(objB, currentKey) || + !objectIs(objA[currentKey], objB[currentKey]) + ) { + return false; } } + + return true; } -/** - * This plugin creates an `onSelect` event that normalizes select events - * across form elements. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - contentEditable - * - * This differs from native browser implementations in the following ways: - * - Fires on contentEditable fields as well as inputs. - * - Fires for collapsed selection. - * - Fires after user input. - */ -function extractEvents$2( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var targetNode = targetInst ? getNodeFromInstance(targetInst) : window; +var ReactStrictModeWarnings = { + recordUnsafeLifecycleWarnings: function (fiber, instance) {}, + flushPendingUnsafeLifecycleWarnings: function () {}, + recordLegacyContextWarning: function (fiber, instance) {}, + flushLegacyContextWarning: function () {}, + discardPendingWarnings: function () {} +}; - switch (domEventName) { - // Track the input node that has focus. - case "focusin": - if ( - isTextInputElement(targetNode) || - targetNode.contentEditable === "true" - ) { - activeElement = targetNode; - activeElementInst = targetInst; - lastSelection = null; +{ + var findStrictRoot = function (fiber) { + var maybeStrictRoot = null; + var node = fiber; + + while (node !== null) { + if (node.mode & StrictLegacyMode) { + maybeStrictRoot = node; } - break; + node = node.return; + } - case "focusout": - activeElement = null; - activeElementInst = null; - lastSelection = null; - break; - // Don't fire the event while the user is dragging. This matches the - // semantics of the native select event. + return maybeStrictRoot; + }; - case "mousedown": - mouseDown = true; - break; + var setToSortedString = function (set) { + var array = []; + set.forEach(function (value) { + array.push(value); + }); + return array.sort().join(", "); + }; - case "contextmenu": - case "mouseup": - case "dragend": - mouseDown = false; - constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget); - break; - // Chrome and IE fire non-standard event when selection is changed (and - // sometimes when it hasn't). IE's event fires out of order with respect - // to key and input events on deletion, so we discard it. - // - // Firefox doesn't support selectionchange, so check selection status - // after each key entry. The selection changes after keydown and before - // keyup, but we check on keydown as well in the case of holding down a - // key, when multiple keydown events are fired but only one keyup is. - // This is also our approach for IE handling, for the reason above. + var pendingComponentWillMountWarnings = []; + var pendingUNSAFE_ComponentWillMountWarnings = []; + var pendingComponentWillReceivePropsWarnings = []; + var pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + var pendingComponentWillUpdateWarnings = []; + var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about. - case "selectionchange": - if (skipSelectionChangeEvent) { - break; - } + var didWarnAboutUnsafeLifecycles = new Set(); - // falls through + ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function ( + fiber, + instance + ) { + // Dedupe strategy: Warn once per component. + if (didWarnAboutUnsafeLifecycles.has(fiber.type)) { + return; + } - case "keydown": - case "keyup": - constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget); - } -} + if ( + typeof instance.componentWillMount === "function" && // Don't warn about react-lifecycles-compat polyfilled components. + instance.componentWillMount.__suppressDeprecationWarning !== true + ) { + pendingComponentWillMountWarnings.push(fiber); + } -/** - * Generate a mapping of standard vendor prefixes using the defined style property and event name. - * - * @param {string} styleProp - * @param {string} eventName - * @returns {object} - */ + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillMount === "function" + ) { + pendingUNSAFE_ComponentWillMountWarnings.push(fiber); + } -function makePrefixMap(styleProp, eventName) { - var prefixes = {}; - prefixes[styleProp.toLowerCase()] = eventName.toLowerCase(); - prefixes["Webkit" + styleProp] = "webkit" + eventName; - prefixes["Moz" + styleProp] = "moz" + eventName; - return prefixes; -} -/** - * A list of event names to a configurable list of vendor prefixes. - */ + if ( + typeof instance.componentWillReceiveProps === "function" && + instance.componentWillReceiveProps.__suppressDeprecationWarning !== true + ) { + pendingComponentWillReceivePropsWarnings.push(fiber); + } -var vendorPrefixes = { - animationend: makePrefixMap("Animation", "AnimationEnd"), - animationiteration: makePrefixMap("Animation", "AnimationIteration"), - animationstart: makePrefixMap("Animation", "AnimationStart"), - transitionend: makePrefixMap("Transition", "TransitionEnd") -}; -/** - * Event names that have already been detected and prefixed (if applicable). - */ + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillReceiveProps === "function" + ) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber); + } -var prefixedEventNames = {}; -/** - * Element to check for prefixes on. - */ + if ( + typeof instance.componentWillUpdate === "function" && + instance.componentWillUpdate.__suppressDeprecationWarning !== true + ) { + pendingComponentWillUpdateWarnings.push(fiber); + } -var style = {}; -/** - * Bootstrap if a DOM exists. - */ + if ( + fiber.mode & StrictLegacyMode && + typeof instance.UNSAFE_componentWillUpdate === "function" + ) { + pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber); + } + }; -if (canUseDOM) { - style = document.createElement("div").style; // On some platforms, in particular some releases of Android 4.x, - // the un-prefixed "animation" and "transition" properties are defined on the - // style object but the events that fire will still be prefixed, so we need - // to check if the un-prefixed events are usable, and if not remove them from the map. + ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () { + // We do an initial pass to gather component names + var componentWillMountUniqueNames = new Set(); - if (!("AnimationEvent" in window)) { - delete vendorPrefixes.animationend.animation; - delete vendorPrefixes.animationiteration.animation; - delete vendorPrefixes.animationstart.animation; - } // Same as above + if (pendingComponentWillMountWarnings.length > 0) { + pendingComponentWillMountWarnings.forEach(function (fiber) { + componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillMountWarnings = []; + } - if (!("TransitionEvent" in window)) { - delete vendorPrefixes.transitionend.transition; - } -} -/** - * Attempts to determine the correct vendor prefixed event name. - * - * @param {string} eventName - * @returns {string} - */ + var UNSAFE_componentWillMountUniqueNames = new Set(); -function getVendorPrefixedEventName(eventName) { - if (prefixedEventNames[eventName]) { - return prefixedEventNames[eventName]; - } else if (!vendorPrefixes[eventName]) { - return eventName; - } + if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) { + pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) { + UNSAFE_componentWillMountUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillMountWarnings = []; + } - var prefixMap = vendorPrefixes[eventName]; + var componentWillReceivePropsUniqueNames = new Set(); - for (var styleProp in prefixMap) { - if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) { - return (prefixedEventNames[eventName] = prefixMap[styleProp]); + if (pendingComponentWillReceivePropsWarnings.length > 0) { + pendingComponentWillReceivePropsWarnings.forEach(function (fiber) { + componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillReceivePropsWarnings = []; } - } - return eventName; -} + var UNSAFE_componentWillReceivePropsUniqueNames = new Set(); -var ANIMATION_END = getVendorPrefixedEventName("animationend"); -var ANIMATION_ITERATION = getVendorPrefixedEventName("animationiteration"); -var ANIMATION_START = getVendorPrefixedEventName("animationstart"); -var TRANSITION_END = getVendorPrefixedEventName("transitionend"); + if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) { + pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) { + UNSAFE_componentWillReceivePropsUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + } -var topLevelEventsToReactNames = new Map(); // NOTE: Capitalization is important in this list! -// -// E.g. it needs "pointerDown", not "pointerdown". -// This is because we derive both React name ("onPointerDown") -// and DOM name ("pointerdown") from the same list. -// -// Exceptions that don't match this convention are listed separately. -// -// prettier-ignore + var componentWillUpdateUniqueNames = new Set(); -var simpleEventPluginEvents = ['abort', 'auxClick', 'cancel', 'canPlay', 'canPlayThrough', 'click', 'close', 'contextMenu', 'copy', 'cut', 'drag', 'dragEnd', 'dragEnter', 'dragExit', 'dragLeave', 'dragOver', 'dragStart', 'drop', 'durationChange', 'emptied', 'encrypted', 'ended', 'error', 'gotPointerCapture', 'input', 'invalid', 'keyDown', 'keyPress', 'keyUp', 'load', 'loadedData', 'loadedMetadata', 'loadStart', 'lostPointerCapture', 'mouseDown', 'mouseMove', 'mouseOut', 'mouseOver', 'mouseUp', 'paste', 'pause', 'play', 'playing', 'pointerCancel', 'pointerDown', 'pointerMove', 'pointerOut', 'pointerOver', 'pointerUp', 'progress', 'rateChange', 'reset', 'resize', 'seeked', 'seeking', 'stalled', 'submit', 'suspend', 'timeUpdate', 'touchCancel', 'touchEnd', 'touchStart', 'volumeChange', 'scroll', 'toggle', 'touchMove', 'waiting', 'wheel']; + if (pendingComponentWillUpdateWarnings.length > 0) { + pendingComponentWillUpdateWarnings.forEach(function (fiber) { + componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingComponentWillUpdateWarnings = []; + } -{ - // Special case: these two events don't have on* React handler - // and are only accessible via the createEventHandle API. - topLevelEventsToReactNames.set("beforeblur", null); - topLevelEventsToReactNames.set("afterblur", null); -} + var UNSAFE_componentWillUpdateUniqueNames = new Set(); -function registerSimpleEvent(domEventName, reactName) { - topLevelEventsToReactNames.set(domEventName, reactName); - registerTwoPhaseEvent(reactName, [domEventName]); -} + if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) { + pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) { + UNSAFE_componentWillUpdateUniqueNames.add( + getComponentNameFromFiber(fiber) || "Component" + ); + didWarnAboutUnsafeLifecycles.add(fiber.type); + }); + pendingUNSAFE_ComponentWillUpdateWarnings = []; + } // Finally, we flush all the warnings + // UNSAFE_ ones before the deprecated ones, since they'll be 'louder' -function registerSimpleEvents() { - for (var i = 0; i < simpleEventPluginEvents.length; i++) { - var eventName = simpleEventPluginEvents[i]; - var domEventName = eventName.toLowerCase(); - var capitalizedEvent = eventName[0].toUpperCase() + eventName.slice(1); - registerSimpleEvent(domEventName, "on" + capitalizedEvent); - } // Special cases where event names don't match. + if (UNSAFE_componentWillMountUniqueNames.size > 0) { + var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames); - registerSimpleEvent(ANIMATION_END, "onAnimationEnd"); - registerSimpleEvent(ANIMATION_ITERATION, "onAnimationIteration"); - registerSimpleEvent(ANIMATION_START, "onAnimationStart"); - registerSimpleEvent("dblclick", "onDoubleClick"); - registerSimpleEvent("focusin", "onFocus"); - registerSimpleEvent("focusout", "onBlur"); - registerSimpleEvent(TRANSITION_END, "onTransitionEnd"); -} + error( + "Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "\nPlease update the following components: %s", + sortedNames + ); + } -function extractEvents$1( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - var reactName = topLevelEventsToReactNames.get(domEventName); + if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames = setToSortedString( + UNSAFE_componentWillReceivePropsUniqueNames + ); - if (reactName === undefined) { - return; - } + error( + "Using UNSAFE_componentWillReceiveProps in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, " + + "refactor your code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "\nPlease update the following components: %s", + _sortedNames + ); + } - var SyntheticEventCtor = SyntheticEvent; - var reactEventType = domEventName; + if (UNSAFE_componentWillUpdateUniqueNames.size > 0) { + var _sortedNames2 = setToSortedString( + UNSAFE_componentWillUpdateUniqueNames + ); - switch (domEventName) { - case "keypress": - // Firefox creates a keypress event for function keys too. This removes - // the unwanted keypress events. Enter is however both printable and - // non-printable. One would expect Tab to be as well (but it isn't). - if (getEventCharCode(nativeEvent) === 0) { - return; - } + error( + "Using UNSAFE_componentWillUpdate in strict mode is not recommended " + + "and may indicate bugs in your code. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "\nPlease update the following components: %s", + _sortedNames2 + ); + } - /* falls through */ + if (componentWillMountUniqueNames.size > 0) { + var _sortedNames3 = setToSortedString(componentWillMountUniqueNames); - case "keydown": - case "keyup": - SyntheticEventCtor = SyntheticKeyboardEvent; - break; + warn( + "componentWillMount has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move code with side effects to componentDidMount, and set initial state in the constructor.\n" + + "* Rename componentWillMount to UNSAFE_componentWillMount to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames3 + ); + } - case "focusin": - reactEventType = "focus"; - SyntheticEventCtor = SyntheticFocusEvent; - break; + if (componentWillReceivePropsUniqueNames.size > 0) { + var _sortedNames4 = setToSortedString( + componentWillReceivePropsUniqueNames + ); - case "focusout": - reactEventType = "blur"; - SyntheticEventCtor = SyntheticFocusEvent; - break; + warn( + "componentWillReceiveProps has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* If you're updating state whenever props change, refactor your " + + "code to use memoization techniques or move it to " + + "static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n" + + "* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames4 + ); + } - case "beforeblur": - case "afterblur": - SyntheticEventCtor = SyntheticFocusEvent; - break; + if (componentWillUpdateUniqueNames.size > 0) { + var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames); - case "click": - // Firefox creates a click event on right mouse clicks. This removes the - // unwanted click events. - if (nativeEvent.button === 2) { - return; - } + warn( + "componentWillUpdate has been renamed, and is not recommended for use. " + + "See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n" + + "* Move data fetching code or side effects to componentDidUpdate.\n" + + "* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress " + + "this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. " + + "To rename all deprecated lifecycles to their new names, you can run " + + "`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n" + + "\nPlease update the following components: %s", + _sortedNames5 + ); + } + }; - /* falls through */ + var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about. - case "auxclick": - case "dblclick": - case "mousedown": - case "mousemove": - case "mouseup": // TODO: Disabled elements should not respond to mouse events + var didWarnAboutLegacyContext = new Set(); - /* falls through */ + ReactStrictModeWarnings.recordLegacyContextWarning = function ( + fiber, + instance + ) { + var strictRoot = findStrictRoot(fiber); - case "mouseout": - case "mouseover": - case "contextmenu": - SyntheticEventCtor = SyntheticMouseEvent; - break; + if (strictRoot === null) { + error( + "Expected to find a StrictMode component in a strict mode tree. " + + "This error is likely caused by a bug in React. Please file an issue." + ); - case "drag": - case "dragend": - case "dragenter": - case "dragexit": - case "dragleave": - case "dragover": - case "dragstart": - case "drop": - SyntheticEventCtor = SyntheticDragEvent; - break; + return; + } // Dedup strategy: Warn once per component. - case "touchcancel": - case "touchend": - case "touchmove": - case "touchstart": - SyntheticEventCtor = SyntheticTouchEvent; - break; + if (didWarnAboutLegacyContext.has(fiber.type)) { + return; + } - case ANIMATION_END: - case ANIMATION_ITERATION: - case ANIMATION_START: - SyntheticEventCtor = SyntheticAnimationEvent; - break; + var warningsForRoot = pendingLegacyContextWarning.get(strictRoot); - case TRANSITION_END: - SyntheticEventCtor = SyntheticTransitionEvent; - break; + if ( + fiber.type.contextTypes != null || + fiber.type.childContextTypes != null || + (instance !== null && typeof instance.getChildContext === "function") + ) { + if (warningsForRoot === undefined) { + warningsForRoot = []; + pendingLegacyContextWarning.set(strictRoot, warningsForRoot); + } - case "scroll": - SyntheticEventCtor = SyntheticUIEvent; - break; + warningsForRoot.push(fiber); + } + }; - case "wheel": - SyntheticEventCtor = SyntheticWheelEvent; - break; + ReactStrictModeWarnings.flushLegacyContextWarning = function () { + pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) { + if (fiberArray.length === 0) { + return; + } - case "copy": - case "cut": - case "paste": - SyntheticEventCtor = SyntheticClipboardEvent; - break; + var firstFiber = fiberArray[0]; + var uniqueNames = new Set(); + fiberArray.forEach(function (fiber) { + uniqueNames.add(getComponentNameFromFiber(fiber) || "Component"); + didWarnAboutLegacyContext.add(fiber.type); + }); + var sortedNames = setToSortedString(uniqueNames); - case "gotpointercapture": - case "lostpointercapture": - case "pointercancel": - case "pointerdown": - case "pointermove": - case "pointerout": - case "pointerover": - case "pointerup": - SyntheticEventCtor = SyntheticPointerEvent; - break; - } + try { + setCurrentFiber(firstFiber); - var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0; + error( + "Legacy context API has been detected within a strict-mode tree." + + "\n\nThe old API will be supported in all 16.x releases, but applications " + + "using it should migrate to the new version." + + "\n\nPlease update the following components: %s" + + "\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context", + sortedNames + ); + } finally { + resetCurrentFiber(); + } + }); + }; - if (eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) { - var listeners = accumulateEventHandleNonManagedNodeListeners( - // TODO: this cast may not make sense for events like - // "focus" where React listens to e.g. "focusin". - reactEventType, - targetContainer, - inCapturePhase - ); + ReactStrictModeWarnings.discardPendingWarnings = function () { + pendingComponentWillMountWarnings = []; + pendingUNSAFE_ComponentWillMountWarnings = []; + pendingComponentWillReceivePropsWarnings = []; + pendingUNSAFE_ComponentWillReceivePropsWarnings = []; + pendingComponentWillUpdateWarnings = []; + pendingUNSAFE_ComponentWillUpdateWarnings = []; + pendingLegacyContextWarning = new Map(); + }; +} - if (listeners.length > 0) { - // Intentionally create event lazily. - var event = new SyntheticEventCtor( - reactName, - reactEventType, - null, - nativeEvent, - nativeEventTarget - ); - dispatchQueue.push({ - event: event, - listeners: listeners - }); - } - } else { - // Some events don't bubble in the browser. - // In the past, React has always bubbled them, but this can be surprising. - // We're going to try aligning closer to the browser behavior by not bubbling - // them in React either. We'll start by not bubbling onScroll, and then expand. - var accumulateTargetOnly = - !inCapturePhase && // TODO: ideally, we'd eventually add all events from - // nonDelegatedEvents list in DOMPluginEventSystem. - // Then we can remove this special list. - // This is a breaking change that can wait until React 18. - domEventName === "scroll"; +var ReactCurrentActQueue$2 = ReactSharedInternals.ReactCurrentActQueue; // An error that is thrown (e.g. by `use`) to trigger Suspense. If we +// detect this is caught by userspace, we'll log a warning in development. - var _listeners = accumulateSinglePhaseListeners( - targetInst, - reactName, - nativeEvent.type, - inCapturePhase, - accumulateTargetOnly, - nativeEvent - ); +var SuspenseException = new Error( + "Suspense Exception: This is not a real error! It's an implementation " + + "detail of `use` to interrupt the current render. You must either " + + "rethrow it immediately, or move the `use` call outside of the " + + "`try/catch` block. Capturing without rethrowing will lead to " + + "unexpected behavior.\n\n" + + "To handle async errors, wrap your component in an error boundary, or " + + "call the promise's `.catch` method and pass the result to `use`" +); +function createThenableState() { + // The ThenableState is created the first time a component suspends. If it + // suspends again, we'll reuse the same state. + return []; +} +function isThenableResolved(thenable) { + var status = thenable.status; + return status === "fulfilled" || status === "rejected"; +} - if (_listeners.length > 0) { - // Intentionally create event lazily. - var _event = new SyntheticEventCtor( - reactName, - reactEventType, - null, - nativeEvent, - nativeEventTarget - ); +function noop$1() {} - dispatchQueue.push({ - event: _event, - listeners: _listeners - }); - } +function trackUsedThenable(thenableState, thenable, index) { + if (ReactCurrentActQueue$2.current !== null) { + ReactCurrentActQueue$2.didUsePromise = true; } -} -registerSimpleEvents(); -registerEvents$1(); -registerEvents$2(); -registerEvents(); -registerEvents$3(); + var previous = thenableState[index]; -function extractEvents( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer -) { - // TODO: we should remove the concept of a "SimpleEventPlugin". - // This is the basic functionality of the event system. All - // the other plugins are essentially polyfills. So the plugin - // should probably be inlined somewhere and have its logic - // be core the to event system. This would potentially allow - // us to ship builds of React without the polyfilled plugins below. - extractEvents$1( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer - ); - var shouldProcessPolyfillPlugins = - (eventSystemFlags & SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS) === 0; // We don't process these events unless we are in the - // event's native "bubble" phase, which means that we're - // not in the capture phase. That's because we emulate - // the capture phase here still. This is a trade-off, - // because in an ideal world we would not emulate and use - // the phases properly, like we do with the SimpleEvent - // plugin. However, the plugins below either expect - // emulation (EnterLeave) or use state localized to that - // plugin (BeforeInput, Change, Select). The state in - // these modules complicates things, as you'll essentially - // get the case where the capture phase event might change - // state, only for the following bubble event to come in - // later and not trigger anything as the state now - // invalidates the heuristics of the event plugin. We - // could alter all these plugins to work in such ways, but - // that might cause other unknown side-effects that we - // can't foresee right now. - - if (shouldProcessPolyfillPlugins) { - extractEvents$3( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractEvents$4( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractEvents$2( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - extractEvents$5( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget - ); - } -} // List of events that need to be individually attached to media elements. - -var mediaEventTypes = [ - "abort", - "canplay", - "canplaythrough", - "durationchange", - "emptied", - "encrypted", - "ended", - "error", - "loadeddata", - "loadedmetadata", - "loadstart", - "pause", - "play", - "playing", - "progress", - "ratechange", - "resize", - "seeked", - "seeking", - "stalled", - "suspend", - "timeupdate", - "volumechange", - "waiting" -]; // We should not delegate these events to the container, but rather -// set them on the actual target element itself. This is primarily -// because these events do not consistently bubble in the DOM. + if (previous === undefined) { + thenableState.push(thenable); + } else { + if (previous !== thenable) { + // Reuse the previous thenable, and drop the new one. We can assume + // they represent the same value, because components are idempotent. + // Avoid an unhandled rejection errors for the Promises that we'll + // intentionally ignore. + thenable.then(noop$1, noop$1); + thenable = previous; + } + } // We use an expando to track the status and result of a thenable so that we + // can synchronously unwrap the value. Think of this as an extension of the + // Promise API, or a custom interface that is a superset of Thenable. + // + // If the thenable doesn't have a status, set it to "pending" and attach + // a listener that will update its status and result when it resolves. -var nonDelegatedEvents = new Set( - ["cancel", "close", "invalid", "load", "scroll", "toggle"].concat( - mediaEventTypes - ) -); + switch (thenable.status) { + case "fulfilled": { + var fulfilledValue = thenable.value; + return fulfilledValue; + } -function executeDispatch(event, listener, currentTarget) { - var type = event.type || "unknown-event"; - event.currentTarget = currentTarget; - invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event); - event.currentTarget = null; -} + case "rejected": { + var rejectedError = thenable.reason; + throw rejectedError; + } -function processDispatchQueueItemsInOrder( - event, - dispatchListeners, - inCapturePhase -) { - var previousInstance; + default: { + if (typeof thenable.status === "string") { + // Only instrument the thenable if the status if not defined. If + // it's defined, but an unknown value, assume it's been instrumented by + // some custom userspace implementation. We treat it as "pending". + // Attach a dummy listener, to ensure that any lazy initialization can + // happen. Flight lazily parses JSON when the value is actually awaited. + thenable.then(noop$1, noop$1); + } else { + var pendingThenable = thenable; + pendingThenable.status = "pending"; + pendingThenable.then( + function (fulfilledValue) { + if (thenable.status === "pending") { + var fulfilledThenable = thenable; + fulfilledThenable.status = "fulfilled"; + fulfilledThenable.value = fulfilledValue; + } + }, + function (error) { + if (thenable.status === "pending") { + var rejectedThenable = thenable; + rejectedThenable.status = "rejected"; + rejectedThenable.reason = error; + } + } + ); + } // Check one more time in case the thenable resolved synchronously. - if (inCapturePhase) { - for (var i = dispatchListeners.length - 1; i >= 0; i--) { - var _dispatchListeners$i = dispatchListeners[i], - instance = _dispatchListeners$i.instance, - currentTarget = _dispatchListeners$i.currentTarget, - listener = _dispatchListeners$i.listener; + switch (thenable.status) { + case "fulfilled": { + var fulfilledThenable = thenable; + return fulfilledThenable.value; + } - if (instance !== previousInstance && event.isPropagationStopped()) { - return; - } + case "rejected": { + var rejectedThenable = thenable; + throw rejectedThenable.reason; + } + } // Suspend. + // + // Throwing here is an implementation detail that allows us to unwind the + // call stack. But we shouldn't allow it to leak into userspace. Throw an + // opaque placeholder value instead of the actual thenable. If it doesn't + // get captured by the work loop, log a warning, because that means + // something in userspace must have caught it. - executeDispatch(event, listener, currentTarget); - previousInstance = instance; - } - } else { - for (var _i = 0; _i < dispatchListeners.length; _i++) { - var _dispatchListeners$_i = dispatchListeners[_i], - _instance = _dispatchListeners$_i.instance, - _currentTarget = _dispatchListeners$_i.currentTarget, - _listener = _dispatchListeners$_i.listener; + suspendedThenable = thenable; - if (_instance !== previousInstance && event.isPropagationStopped()) { - return; + { + needsToResetSuspendedThenableDEV = true; } - executeDispatch(event, _listener, _currentTarget); - previousInstance = _instance; + throw SuspenseException; } } -} - -function processDispatchQueue(dispatchQueue, eventSystemFlags) { - var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0; - - for (var i = 0; i < dispatchQueue.length; i++) { - var _dispatchQueue$i = dispatchQueue[i], - event = _dispatchQueue$i.event, - listeners = _dispatchQueue$i.listeners; - processDispatchQueueItemsInOrder(event, listeners, inCapturePhase); // event system doesn't use pooling. - } // This would be a good time to rethrow if any of the event handlers threw. +} // This is used to track the actual thenable that suspended so it can be +// passed to the rest of the Suspense implementation — which, for historical +// reasons, expects to receive a thenable. - rethrowCaughtError(); -} +var suspendedThenable = null; +var needsToResetSuspendedThenableDEV = false; +function getSuspendedThenable() { + // This is called right after `use` suspends by throwing an exception. `use` + // throws an opaque value instead of the thenable itself so that it can't be + // caught in userspace. Then the work loop accesses the actual thenable using + // this function. + if (suspendedThenable === null) { + throw new Error( + "Expected a suspended thenable. This is a bug in React. Please file " + + "an issue." + ); + } -function dispatchEventsForPlugins( - domEventName, - eventSystemFlags, - nativeEvent, - targetInst, - targetContainer -) { - var nativeEventTarget = getEventTarget(nativeEvent); - var dispatchQueue = []; - extractEvents( - dispatchQueue, - domEventName, - targetInst, - nativeEvent, - nativeEventTarget, - eventSystemFlags, - targetContainer - ); - processDispatchQueue(dispatchQueue, eventSystemFlags); -} + var thenable = suspendedThenable; + suspendedThenable = null; -function listenToNonDelegatedEvent(domEventName, targetElement) { { - if (!nonDelegatedEvents.has(domEventName)) { - error( - 'Did not expect a listenToNonDelegatedEvent() call for "%s". ' + - "This is a bug in React. Please file an issue.", - domEventName - ); - } + needsToResetSuspendedThenableDEV = false; } - var isCapturePhaseListener = false; - var listenerSet = getEventListenerSet(targetElement); - var listenerSetKey = getListenerSetKey(domEventName, isCapturePhaseListener); - - if (!listenerSet.has(listenerSetKey)) { - addTrappedEventListener( - targetElement, - domEventName, - IS_NON_DELEGATED, - isCapturePhaseListener - ); - listenerSet.add(listenerSetKey); - } + return thenable; } -function listenToNativeEvent(domEventName, isCapturePhaseListener, target) { +function checkIfUseWrappedInTryCatch() { { - if (nonDelegatedEvents.has(domEventName) && !isCapturePhaseListener) { - error( - 'Did not expect a listenToNativeEvent() call for "%s" in the bubble phase. ' + - "This is a bug in React. Please file an issue.", - domEventName - ); + // This was set right before SuspenseException was thrown, and it should + // have been cleared when the exception was handled. If it wasn't, + // it must have been caught by userspace. + if (needsToResetSuspendedThenableDEV) { + needsToResetSuspendedThenableDEV = false; + return true; } } - var eventSystemFlags = 0; + return false; +} - if (isCapturePhaseListener) { - eventSystemFlags |= IS_CAPTURE_PHASE; - } +var thenableState$1 = null; +var thenableIndexCounter$1 = 0; +var didWarnAboutMaps; +var didWarnAboutGenerators; +var didWarnAboutStringRefs; +var ownerHasKeyUseWarning; +var ownerHasFunctionTypeWarning; - addTrappedEventListener( - target, - domEventName, - eventSystemFlags, - isCapturePhaseListener - ); -} // This is only used by createEventHandle when the -// target is not a DOM element. E.g. window. +var warnForMissingKey = function (child, returnFiber) {}; -function listenToNativeEventForNonManagedEventTarget( - domEventName, - isCapturePhaseListener, - target -) { - var eventSystemFlags = IS_EVENT_HANDLE_NON_MANAGED_NODE; - var listenerSet = getEventListenerSet(target); - var listenerSetKey = getListenerSetKey(domEventName, isCapturePhaseListener); +{ + didWarnAboutMaps = false; + didWarnAboutGenerators = false; + didWarnAboutStringRefs = {}; + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ - if (!listenerSet.has(listenerSetKey)) { - if (isCapturePhaseListener) { - eventSystemFlags |= IS_CAPTURE_PHASE; + ownerHasKeyUseWarning = {}; + ownerHasFunctionTypeWarning = {}; + + warnForMissingKey = function (child, returnFiber) { + if (child === null || typeof child !== "object") { + return; } - addTrappedEventListener( - target, - domEventName, - eventSystemFlags, - isCapturePhaseListener - ); - listenerSet.add(listenerSetKey); - } -} -var listeningMarker = "_reactListening" + Math.random().toString(36).slice(2); -function listenToAllSupportedEvents(rootContainerElement) { - if (!rootContainerElement[listeningMarker]) { - rootContainerElement[listeningMarker] = true; - allNativeEvents.forEach(function (domEventName) { - // We handle selectionchange separately because it - // doesn't bubble and needs to be on the document. - if (domEventName !== "selectionchange") { - if (!nonDelegatedEvents.has(domEventName)) { - listenToNativeEvent(domEventName, false, rootContainerElement); - } + if (!child._store || child._store.validated || child.key != null) { + return; + } - listenToNativeEvent(domEventName, true, rootContainerElement); - } - }); - var ownerDocument = - rootContainerElement.nodeType === DOCUMENT_NODE - ? rootContainerElement - : rootContainerElement.ownerDocument; + if (typeof child._store !== "object") { + throw new Error( + "React Component in warnForMissingKey should have a _store. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + } // $FlowFixMe unable to narrow type from mixed to writable object - if (ownerDocument !== null) { - // The selectionchange event also needs deduplication - // but it is attached to the document. - if (!ownerDocument[listeningMarker]) { - ownerDocument[listeningMarker] = true; - listenToNativeEvent("selectionchange", false, ownerDocument); - } + child._store.validated = true; + var componentName = getComponentNameFromFiber(returnFiber) || "Component"; + + if (ownerHasKeyUseWarning[componentName]) { + return; } - } + + ownerHasKeyUseWarning[componentName] = true; + + error( + "Each child in a list should have a unique " + + '"key" prop. See https://reactjs.org/link/warning-keys for ' + + "more information." + ); + }; } -function addTrappedEventListener( - targetContainer, - domEventName, - eventSystemFlags, - isCapturePhaseListener, - isDeferredListenerForLegacyFBSupport -) { - var listener = createEventListenerWrapperWithPriority( - targetContainer, - domEventName, - eventSystemFlags - ); // If passive option is not supported, then the event will be - // active and not passive. +function isReactClass(type) { + return type.prototype && type.prototype.isReactComponent; +} - var isPassiveListener = undefined; +function unwrapThenable(thenable) { + var index = thenableIndexCounter$1; + thenableIndexCounter$1 += 1; - if (passiveBrowserEventsSupported) { - // Browsers introduced an intervention, making these events - // passive by default on document. React doesn't bind them - // to document anymore, but changing this now would undo - // the performance wins from the change. So we emulate - // the existing behavior manually on the roots now. - // https://github.com/facebook/react/issues/19651 - if ( - domEventName === "touchstart" || - domEventName === "touchmove" || - domEventName === "wheel" - ) { - isPassiveListener = true; - } + if (thenableState$1 === null) { + thenableState$1 = createThenableState(); } - targetContainer = - enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport - ? targetContainer.ownerDocument - : targetContainer; - var unsubscribeListener; // When legacyFBSupport is enabled, it's for when we - // want to add a one time event listener to a container. - // This should only be used with enableLegacyFBSupport - // due to requirement to provide compatibility with - // internal FB www event tooling. This works by removing - // the event listener as soon as it is invoked. We could - // also attempt to use the {once: true} param on - // addEventListener, but that requires support and some - // browsers do not support this today, and given this is - // to support legacy code patterns, it's likely they'll - // need support for such browsers. - - if (enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport) { - var originalListener = listener; // $FlowFixMe[missing-this-annot] - // $FlowFixMe[definition-cycle] + return trackUsedThenable(thenableState$1, thenable, index); +} - listener = function () { - removeEventListener( - targetContainer, - domEventName, - unsubscribeListener, - isCapturePhaseListener - ); +function coerceRef(returnFiber, current, element) { + var mixedRef = element.ref; - for ( - var _len = arguments.length, p = new Array(_len), _key = 0; - _key < _len; - _key++ + if ( + mixedRef !== null && + typeof mixedRef !== "function" && + typeof mixedRef !== "object" + ) { + { + if ( + // We warn in ReactElement.js if owner and self are equal for string refs + // because these cannot be automatically converted to an arrow function + // using a codemod. Therefore, we don't have to warn about string refs again. + !( + element._owner && + element._self && + element._owner.stateNode !== element._self + ) && // Will already throw with "Function components cannot have string refs" + !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with "Function components cannot be given refs" + !(typeof element.type === "function" && !isReactClass(element.type)) && // Will already throw with "Element ref was specified as a string (someStringRef) but no owner was set" + element._owner ) { - p[_key] = arguments[_key]; - } + var componentName = + getComponentNameFromFiber(returnFiber) || "Component"; - return originalListener.apply(this, p); - }; - } // TODO: There are too many combinations here. Consolidate them. + if (!didWarnAboutStringRefs[componentName]) { + error( + 'Component "%s" contains the string ref "%s". Support for string refs ' + + "will be removed in a future major release. We recommend using " + + "useRef() or createRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref", + componentName, + mixedRef + ); - if (isCapturePhaseListener) { - if (isPassiveListener !== undefined) { - unsubscribeListener = addEventCaptureListenerWithPassiveFlag( - targetContainer, - domEventName, - listener, - isPassiveListener - ); - } else { - unsubscribeListener = addEventCaptureListener( - targetContainer, - domEventName, - listener - ); - } - } else { - if (isPassiveListener !== undefined) { - unsubscribeListener = addEventBubbleListenerWithPassiveFlag( - targetContainer, - domEventName, - listener, - isPassiveListener - ); - } else { - unsubscribeListener = addEventBubbleListener( - targetContainer, - domEventName, - listener - ); + didWarnAboutStringRefs[componentName] = true; + } + } } - } -} - -function deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer) { - // We defer all click events with legacy FB support mode on. - // This means we add a one time event listener to trigger - // after the FB delegated listeners fire. - var isDeferredListenerForLegacyFBSupport = true; - addTrappedEventListener( - targetContainer, - domEventName, - IS_LEGACY_FB_SUPPORT_MODE, - false, - isDeferredListenerForLegacyFBSupport - ); -} - -function isMatchingRootContainer(grandContainer, targetContainer) { - return ( - grandContainer === targetContainer || - (grandContainer.nodeType === COMMENT_NODE && - grandContainer.parentNode === targetContainer) - ); -} - -function dispatchEventForPluginEventSystem( - domEventName, - eventSystemFlags, - nativeEvent, - targetInst, - targetContainer -) { - var ancestorInst = targetInst; - - if ( - (eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) === 0 && - (eventSystemFlags & IS_NON_DELEGATED) === 0 - ) { - var targetContainerNode = targetContainer; // If we are using the legacy FB support flag, we - // defer the event to the null with a one - // time event listener so we can defer the event. - if ( - enableLegacyFBSupport && // If our event flags match the required flags for entering - // FB legacy mode and we are processing the "click" event, - // then we can defer the event to the "document", to allow - // for legacy FB support, where the expected behavior was to - // match React < 16 behavior of delegated clicks to the doc. - domEventName === "click" && - (eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0 && - !isReplayingEvent(nativeEvent) - ) { - deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer); - return; - } + if (element._owner) { + var owner = element._owner; + var inst; - if (targetInst !== null) { - // The below logic attempts to work out if we need to change - // the target fiber to a different ancestor. We had similar logic - // in the legacy event system, except the big difference between - // systems is that the modern event system now has an event listener - // attached to each React Root and React Portal Root. Together, - // the DOM nodes representing these roots are the "rootContainer". - // To figure out which ancestor instance we should use, we traverse - // up the fiber tree from the target instance and attempt to find - // root boundaries that match that of our current "rootContainer". - // If we find that "rootContainer", we find the parent fiber - // sub-tree for that root and make that our ancestor instance. - var node = targetInst; + if (owner) { + var ownerFiber = owner; - mainLoop: while (true) { - if (node === null) { - return; + if (ownerFiber.tag !== ClassComponent) { + throw new Error( + "Function components cannot have string refs. " + + "We recommend using useRef() instead. " + + "Learn more about using refs safely here: " + + "https://reactjs.org/link/strict-mode-string-ref" + ); } - var nodeTag = node.tag; - - if (nodeTag === HostRoot || nodeTag === HostPortal) { - var container = node.stateNode.containerInfo; - - if (isMatchingRootContainer(container, targetContainerNode)) { - break; - } - - if (nodeTag === HostPortal) { - // The target is a portal, but it's not the rootContainer we're looking for. - // Normally portals handle their own events all the way down to the root. - // So we should be able to stop now. However, we don't know if this portal - // was part of *our* root. - var grandNode = node.return; - - while (grandNode !== null) { - var grandTag = grandNode.tag; - - if (grandTag === HostRoot || grandTag === HostPortal) { - var grandContainer = grandNode.stateNode.containerInfo; + inst = ownerFiber.stateNode; + } - if ( - isMatchingRootContainer(grandContainer, targetContainerNode) - ) { - // This is the rootContainer we're looking for and we found it as - // a parent of the Portal. That means we can ignore it because the - // Portal will bubble through to us. - return; - } - } + if (!inst) { + throw new Error( + "Missing owner for string ref " + + mixedRef + + ". This error is likely caused by a " + + "bug in React. Please file an issue." + ); + } // Assigning this to a const so Flow knows it won't change in the closure - grandNode = grandNode.return; - } - } // Now we need to find it's corresponding host fiber in the other - // tree. To do this we can use getClosestInstanceFromNode, but we - // need to validate that the fiber is a host instance, otherwise - // we need to traverse up through the DOM till we find the correct - // node that is from the other tree. + var resolvedInst = inst; - while (container !== null) { - var parentNode = getClosestInstanceFromNode(container); + { + checkPropStringCoercion(mixedRef, "ref"); + } - if (parentNode === null) { - return; - } + var stringRef = "" + mixedRef; // Check if previous string ref matches new string ref - var parentTag = parentNode.tag; + if ( + current !== null && + current.ref !== null && + typeof current.ref === "function" && + current.ref._stringRef === stringRef + ) { + return current.ref; + } - if ( - parentTag === HostComponent || - parentTag === HostText || - parentTag === HostHoistable || - parentTag === HostSingleton - ) { - node = ancestorInst = parentNode; - continue mainLoop; - } + var ref = function (value) { + var refs = resolvedInst.refs; - container = container.parentNode; - } + if (value === null) { + delete refs[stringRef]; + } else { + refs[stringRef] = value; } + }; - node = node.return; + ref._stringRef = stringRef; + return ref; + } else { + if (typeof mixedRef !== "string") { + throw new Error( + "Expected ref to be a function, a string, an object returned by React.createRef(), or null." + ); + } + + if (!element._owner) { + throw new Error( + "Element ref was specified as a string (" + + mixedRef + + ") but no owner was set. This could happen for one of" + + " the following reasons:\n" + + "1. You may be adding a ref to a function component\n" + + "2. You may be adding a ref to a component that was not created inside a component's render method\n" + + "3. You have multiple copies of React loaded\n" + + "See https://reactjs.org/link/refs-must-have-owner for more information." + ); } } } - batchedUpdates$1(function () { - return dispatchEventsForPlugins( - domEventName, - eventSystemFlags, - nativeEvent, - ancestorInst, - targetContainer - ); - }); + return mixedRef; } -function createDispatchListener(instance, listener, currentTarget) { - return { - instance: instance, - listener: listener, - currentTarget: currentTarget - }; +function throwOnInvalidObjectType(returnFiber, newChild) { + // $FlowFixMe[method-unbinding] + var childString = Object.prototype.toString.call(newChild); + throw new Error( + "Objects are not valid as a React child (found: " + + (childString === "[object Object]" + ? "object with keys {" + Object.keys(newChild).join(", ") + "}" + : childString) + + "). " + + "If you meant to render a collection of children, use an array " + + "instead." + ); } -function accumulateSinglePhaseListeners( - targetFiber, - reactName, - nativeEventType, - inCapturePhase, - accumulateTargetOnly, - nativeEvent -) { - var captureName = reactName !== null ? reactName + "Capture" : null; - var reactEventName = inCapturePhase ? captureName : reactName; - var listeners = []; - var instance = targetFiber; - var lastHostComponent = null; // Accumulate all instances and listeners via the target -> root path. - - while (instance !== null) { - var _instance2 = instance, - stateNode = _instance2.stateNode, - tag = _instance2.tag; // Handle listeners that are on HostComponents (i.e.
) +function warnOnFunctionType(returnFiber) { + { + var componentName = getComponentNameFromFiber(returnFiber) || "Component"; - if ( - (tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton) && - stateNode !== null - ) { - lastHostComponent = stateNode; // createEventHandle listeners + if (ownerHasFunctionTypeWarning[componentName]) { + return; + } - { - var eventHandlerListeners = getEventHandlerListeners(lastHostComponent); + ownerHasFunctionTypeWarning[componentName] = true; - if (eventHandlerListeners !== null) { - eventHandlerListeners.forEach(function (entry) { - if ( - entry.type === nativeEventType && - entry.capture === inCapturePhase - ) { - listeners.push( - createDispatchListener( - instance, - entry.callback, - lastHostComponent - ) - ); - } - }); - } - } // Standard React on* listeners, i.e. onClick or onClickCapture + error( + "Functions are not valid as a React child. This may happen if " + + "you return a Component instead of from render. " + + "Or maybe you meant to call this function rather than return it." + ); + } +} - if (reactEventName !== null) { - var listener = getListener(instance, reactEventName); +function resolveLazy(lazyType) { + var payload = lazyType._payload; + var init = lazyType._init; + return init(payload); +} // 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. - if (listener != null) { - listeners.push( - createDispatchListener(instance, listener, lastHostComponent) - ); - } - } - } else if ( - tag === ScopeComponent && - lastHostComponent !== null && - stateNode !== null - ) { - // Scopes - var reactScopeInstance = stateNode; +function createChildReconciler(shouldTrackSideEffects) { + function deleteChild(returnFiber, childToDelete) { + if (!shouldTrackSideEffects) { + // Noop. + return; + } - var _eventHandlerListeners = getEventHandlerListeners(reactScopeInstance); + var deletions = returnFiber.deletions; - if (_eventHandlerListeners !== null) { - _eventHandlerListeners.forEach(function (entry) { - if ( - entry.type === nativeEventType && - entry.capture === inCapturePhase - ) { - listeners.push( - createDispatchListener( - instance, - entry.callback, - lastHostComponent - ) - ); - } - }); - } - } // If we are only accumulating events for the target, then we don't - // continue to propagate through the React fiber tree to find other - // listeners. + if (deletions === null) { + returnFiber.deletions = [childToDelete]; + returnFiber.flags |= ChildDeletion; + } else { + deletions.push(childToDelete); + } + } - if (accumulateTargetOnly) { - break; - } // If we are processing the onBeforeBlur event, then we need to take - // into consideration that part of the React tree might have been hidden - // or deleted (as we're invoking this event during commit). We can find - // this out by checking if intercept fiber set on the event matches the - // current instance fiber. In which case, we should clear all existing - // listeners. + 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. - if (nativeEvent.type === "beforeblur") { - // $FlowFixMe[prop-missing] internal field - var detachedInterceptFiber = nativeEvent._detachedInterceptFiber; + var childToDelete = currentFirstChild; - if ( - detachedInterceptFiber !== null && - (detachedInterceptFiber === instance || - detachedInterceptFiber === instance.alternate) - ) { - listeners = []; - } + while (childToDelete !== null) { + deleteChild(returnFiber, childToDelete); + childToDelete = childToDelete.sibling; } - instance = instance.return; + return null; } - return listeners; -} // We should only use this function for: -// - BeforeInputEventPlugin -// - ChangeEventPlugin -// - SelectEventPlugin -// This is because we only process these plugins -// in the bubble phase, so we need to accumulate two -// phase event listeners (via emulation). - -function accumulateTwoPhaseListeners(targetFiber, reactName) { - var captureName = reactName + "Capture"; - var listeners = []; - var instance = targetFiber; // Accumulate all instances and listeners via the target -> root path. - - while (instance !== null) { - var _instance3 = instance, - stateNode = _instance3.stateNode, - tag = _instance3.tag; // Handle listeners that are on HostComponents (i.e.
) - - if ( - (tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton) && - stateNode !== null - ) { - var currentTarget = stateNode; - var captureListener = getListener(instance, captureName); + 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 + // instead. + var existingChildren = new Map(); + var existingChild = currentFirstChild; - if (captureListener != null) { - listeners.unshift( - createDispatchListener(instance, captureListener, currentTarget) - ); + while (existingChild !== null) { + if (existingChild.key !== null) { + existingChildren.set(existingChild.key, existingChild); + } else { + existingChildren.set(existingChild.index, existingChild); } - var bubbleListener = getListener(instance, reactName); - - if (bubbleListener != null) { - listeners.push( - createDispatchListener(instance, bubbleListener, currentTarget) - ); - } + existingChild = existingChild.sibling; } - instance = instance.return; + return existingChildren; } - return listeners; -} - -function getParent(inst) { - if (inst === null) { - return null; + function useFiber(fiber, pendingProps) { + // 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); + clone.index = 0; + clone.sibling = null; + return clone; } - do { - // $FlowFixMe[incompatible-use] found when upgrading Flow - inst = inst.return; // TODO: If this is a HostRoot we might want to bail out. - // That is depending on if we want nested subtrees (layers) to bubble - // events to their parent. We could also go through parentNode on the - // host node but that wouldn't work for React Native and doesn't let us - // do the portal feature. - } while (inst && inst.tag !== HostComponent && inst.tag !== HostSingleton); + function placeChild(newFiber, lastPlacedIndex, newIndex) { + newFiber.index = newIndex; - if (inst) { - return inst; - } + if (!shouldTrackSideEffects) { + // During hydration, the useId algorithm needs to know which fibers are + // part of a list of children (arrays, iterators). + newFiber.flags |= Forked; + return lastPlacedIndex; + } - return null; -} -/** - * Return the lowest common ancestor of A and B, or null if they are in - * different trees. - */ + var current = newFiber.alternate; -function getLowestCommonAncestor(instA, instB) { - var nodeA = instA; - var nodeB = instB; - var depthA = 0; + if (current !== null) { + var oldIndex = current.index; - for (var tempA = nodeA; tempA; tempA = getParent(tempA)) { - depthA++; + if (oldIndex < lastPlacedIndex) { + // This is a move. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } else { + // This item can stay in place. + return oldIndex; + } + } else { + // This is an insertion. + newFiber.flags |= Placement | PlacementDEV; + return lastPlacedIndex; + } } - var depthB = 0; + 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.flags |= Placement | PlacementDEV; + } - for (var tempB = nodeB; tempB; tempB = getParent(tempB)) { - depthB++; - } // If A is deeper, crawl up. - - while (depthA - depthB > 0) { - nodeA = getParent(nodeA); - depthA--; - } // If B is deeper, crawl up. + return newFiber; + } - while (depthB - depthA > 0) { - nodeB = getParent(nodeB); - depthB--; - } // Walk in lockstep until we find a match. + function updateTextNode(returnFiber, current, textContent, lanes) { + if (current === null || current.tag !== HostText) { + // Insert + var created = createFiberFromText(textContent, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, textContent); + existing.return = returnFiber; + return existing; + } + } - var depth = depthA; + function updateElement(returnFiber, current, element, lanes) { + var elementType = element.type; - while (depth--) { - if (nodeA === nodeB || (nodeB !== null && nodeA === nodeB.alternate)) { - return nodeA; + if (elementType === REACT_FRAGMENT_TYPE) { + return updateFragment( + returnFiber, + current, + element.props.children, + lanes, + element.key + ); } - nodeA = getParent(nodeA); - nodeB = getParent(nodeB); - } + if (current !== null) { + if ( + current.elementType === elementType || // Keep this check inline so it only runs on the false path: + isCompatibleFamilyForHotReloading(current, element) || // Lazy types should reconcile their resolved type. + // We need to do this after the Hot Reloading check above, + // because hot reloading has different semantics than prod because + // it doesn't resuspend. So we can't let the call below suspend. + (typeof elementType === "object" && + elementType !== null && + elementType.$$typeof === REACT_LAZY_TYPE && + resolveLazy(elementType) === current.type) + ) { + // Move based on index + var existing = useFiber(current, element.props); + existing.ref = coerceRef(returnFiber, current, element); + existing.return = returnFiber; - return null; -} + { + existing._debugSource = element._source; + existing._debugOwner = element._owner; + } -function accumulateEnterLeaveListenersForEvent( - dispatchQueue, - event, - target, - common, - inCapturePhase -) { - var registrationName = event._reactName; - var listeners = []; - var instance = target; + return existing; + } + } // Insert - while (instance !== null) { - if (instance === common) { - break; - } + var created = createFiberFromElement(element, returnFiber.mode, lanes); + created.ref = coerceRef(returnFiber, current, element); + created.return = returnFiber; + return created; + } - var _instance4 = instance, - alternate = _instance4.alternate, - stateNode = _instance4.stateNode, - tag = _instance4.tag; + function updatePortal(returnFiber, current, portal, lanes) { + if ( + current === null || + current.tag !== HostPortal || + current.stateNode.containerInfo !== portal.containerInfo || + current.stateNode.implementation !== portal.implementation + ) { + // Insert + var created = createFiberFromPortal(portal, returnFiber.mode, lanes); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, portal.children || []); + existing.return = returnFiber; + return existing; + } + } - if (alternate !== null && alternate === common) { - break; + function updateFragment(returnFiber, current, fragment, lanes, key) { + if (current === null || current.tag !== Fragment) { + // Insert + var created = createFiberFromFragment( + fragment, + returnFiber.mode, + lanes, + key + ); + created.return = returnFiber; + return created; + } else { + // Update + var existing = useFiber(current, fragment); + existing.return = returnFiber; + return existing; } + } + function createChild(returnFiber, newChild, lanes) { if ( - (tag === HostComponent || - tag === HostHoistable || - tag === HostSingleton) && - stateNode !== null + (typeof newChild === "string" && newChild !== "") || + typeof newChild === "number" ) { - var currentTarget = stateNode; - - if (inCapturePhase) { - var captureListener = getListener(instance, registrationName); + // 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, lanes); + created.return = returnFiber; + return created; + } - if (captureListener != null) { - listeners.unshift( - createDispatchListener(instance, captureListener, currentTarget) + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + var _created = createFiberFromElement( + newChild, + returnFiber.mode, + lanes ); + + _created.ref = coerceRef(returnFiber, null, newChild); + _created.return = returnFiber; + return _created; } - } else if (!inCapturePhase) { - var bubbleListener = getListener(instance, registrationName); - if (bubbleListener != null) { - listeners.push( - createDispatchListener(instance, bubbleListener, currentTarget) + case REACT_PORTAL_TYPE: { + var _created2 = createFiberFromPortal( + newChild, + returnFiber.mode, + lanes ); - } - } - } - instance = instance.return; - } + _created2.return = returnFiber; + return _created2; + } - if (listeners.length !== 0) { - dispatchQueue.push({ - event: event, - listeners: listeners - }); - } -} // We should only use this function for: -// - EnterLeaveEventPlugin -// This is because we only process this plugin -// in the bubble phase, so we need to accumulate two -// phase event listeners. + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return createChild(returnFiber, init(payload), lanes); + } + } -function accumulateEnterLeaveTwoPhaseListeners( - dispatchQueue, - leaveEvent, - enterEvent, - from, - to -) { - var common = from && to ? getLowestCommonAncestor(from, to) : null; + if (isArray(newChild) || getIteratorFn(newChild)) { + var _created3 = createFiberFromFragment( + newChild, + returnFiber.mode, + lanes, + null + ); - if (from !== null) { - accumulateEnterLeaveListenersForEvent( - dispatchQueue, - leaveEvent, - from, - common, - false - ); - } + _created3.return = returnFiber; + return _created3; + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - if (to !== null && enterEvent !== null) { - accumulateEnterLeaveListenersForEvent( - dispatchQueue, - enterEvent, - to, - common, - true - ); - } -} -function accumulateEventHandleNonManagedNodeListeners( - reactEventType, - currentTarget, - inCapturePhase -) { - var listeners = []; - var eventListeners = getEventHandlerListeners(currentTarget); + if (typeof newChild.then === "function") { + var thenable = newChild; + return createChild(returnFiber, unwrapThenable(thenable), lanes); + } - if (eventListeners !== null) { - eventListeners.forEach(function (entry) { - if (entry.type === reactEventType && entry.capture === inCapturePhase) { - listeners.push( - createDispatchListener(null, entry.callback, currentTarget) + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return createChild( + returnFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes ); } - }); - } - return listeners; -} -function getListenerSetKey(domEventName, capture) { - return domEventName + "__" + (capture ? "capture" : "bubble"); -} + throwOnInvalidObjectType(returnFiber, newChild); + } -var didWarnInvalidHydration = false; -var didWarnScriptTags = false; -var DANGEROUSLY_SET_INNER_HTML = "dangerouslySetInnerHTML"; -var SUPPRESS_CONTENT_EDITABLE_WARNING = "suppressContentEditableWarning"; -var SUPPRESS_HYDRATION_WARNING$1 = "suppressHydrationWarning"; -var AUTOFOCUS = "autoFocus"; -var CHILDREN = "children"; -var STYLE$1 = "style"; -var HTML = "__html"; -var warnedUnknownTags; -var canDiffStyleForHydrationWarning; + { + if (typeof newChild === "function") { + warnOnFunctionType(returnFiber); + } + } -{ - warnedUnknownTags = { - // There are working polyfills for . Let people use it. - dialog: true, - // Electron ships a custom tag to display external web content in - // an isolated frame and process. - // This tag is not present in non Electron environments such as JSDom which - // is often used for testing purposes. - // @see https://electronjs.org/docs/api/webview-tag - webview: true - }; // IE 11 parses & normalizes the style attribute as opposed to other - // browsers. It adds spaces and sorts the properties in some - // non-alphabetical order. Handling that would require sorting CSS - // properties in the client & server versions or applying - // `expectedStyle` to a temporary DOM node to read its `style` attribute - // normalized. Since it only affects IE, we're skipping style warnings - // in that browser completely in favor of doing all that work. - // See https://github.com/facebook/react/issues/11807 + return null; + } - canDiffStyleForHydrationWarning = canUseDOM && !document.documentMode; -} + function updateSlot(returnFiber, oldFiber, newChild, lanes) { + // Update the fiber if the keys match, otherwise return null. + var key = oldFiber !== null ? oldFiber.key : null; -function validatePropertiesInDevelopment(type, props) { - { - validateProperties$2(type, props); - validateProperties$1(type, props); - validateProperties(type, props, { - registrationNameDependencies: registrationNameDependencies, - possibleRegistrationNames: possibleRegistrationNames - }); - } -} + if ( + (typeof newChild === "string" && newChild !== "") || + 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; + } -function warnForPropDifference(propName, serverValue, clientValue) { - { - if (didWarnInvalidHydration) { - return; + return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes); } - var normalizedClientValue = normalizeMarkupForTextOrAttribute(clientValue); - var normalizedServerValue = normalizeMarkupForTextOrAttribute(serverValue); + if (typeof newChild === "object" && newChild !== null) { + switch (newChild.$$typeof) { + case REACT_ELEMENT_TYPE: { + if (newChild.key === key) { + return updateElement(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - if (normalizedServerValue === normalizedClientValue) { - return; - } + case REACT_PORTAL_TYPE: { + if (newChild.key === key) { + return updatePortal(returnFiber, oldFiber, newChild, lanes); + } else { + return null; + } + } - didWarnInvalidHydration = true; + case REACT_LAZY_TYPE: { + var payload = newChild._payload; + var init = newChild._init; + return updateSlot(returnFiber, oldFiber, init(payload), lanes); + } + } - error( - "Prop `%s` did not match. Server: %s Client: %s", - propName, - JSON.stringify(normalizedServerValue), - JSON.stringify(normalizedClientValue) - ); - } -} + if (isArray(newChild) || getIteratorFn(newChild)) { + if (key !== null) { + return null; + } -function warnForExtraAttributes(attributeNames) { - { - if (didWarnInvalidHydration) { - return; - } + return updateFragment(returnFiber, oldFiber, newChild, lanes, null); + } // Usable node types + // + // Unwrap the inner value and recursively call this function again. - didWarnInvalidHydration = true; - var names = []; - attributeNames.forEach(function (name) { - names.push(name); - }); + if (typeof newChild.then === "function") { + var thenable = newChild; + return updateSlot( + returnFiber, + oldFiber, + unwrapThenable(thenable), + lanes + ); + } - error("Extra attributes from the server: %s", names); - } -} + if ( + newChild.$$typeof === REACT_CONTEXT_TYPE || + newChild.$$typeof === REACT_SERVER_CONTEXT_TYPE + ) { + var context = newChild; + return updateSlot( + returnFiber, + oldFiber, + readContextDuringReconcilation(returnFiber, context, lanes), + lanes + ); + } -function warnForInvalidEventListener(registrationName, listener) { - { - if (listener === false) { - error( - "Expected `%s` listener to be a function, instead got `false`.\n\n" + - "If you used to conditionally omit it with %s={condition && value}, " + - "pass %s={condition ? value : undefined} instead.", - registrationName, - registrationName, - registrationName - ); - } else { - error( - "Expected `%s` listener to be a function, instead got a value of `%s` type.", - registrationName, - typeof listener - ); + throwOnInvalidObjectType(returnFiber, newChild); } - } -} // Parse the HTML and read it back to normalize the HTML string so that it -// can be used for comparison. -function normalizeHTML(parent, html) { - { - // We could have created a separate document here to avoid - // re-initializing custom elements if they exist. But this breaks - // how