Source code

Revision control

Copy as Markdown

Other Tools

/** @license React v16.6.1
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('devtools/client/shared/vendor/react')) :
typeof define === 'function' && define.amd ? define(['devtools/client/shared/vendor/react'], factory) :
(global.ReactDOM = factory(global.React));
}(this, (function (React) { 'use strict';
/**
* Use invariant() to assert state which your program assumes to be true.
*
* Provide sprintf-style format (only %s is supported) and arguments
* to provide information about what broke and what you were
* expecting.
*
* The invariant message will be stripped in production, but the invariant
* will remain to ensure logic does not differ in production.
*/
function invariant(condition, format, a, b, c, d, e, f) {
if (!condition) {
var error = void 0;
if (format === undefined) {
error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
} else {
var args = [a, b, c, d, e, f];
var argIndex = 0;
error = new Error(format.replace(/%s/g, function () {
return args[argIndex++];
}));
error.name = 'Invariant Violation';
}
error.framesToPop = 1; // we don't care about invariant's own frame
throw error;
}
}
// Relying on the `invariant()` implementation lets us
// preserve the format and params in the www builds.
/**
* WARNING: DO NOT manually require this module.
* This is a replacement for `invariant(...)` used by the error code system
* and will _only_ be required by the corresponding babel pass.
* It always throws.
*/
function reactProdInvariant(code) {
var argCount = arguments.length - 1;
for (var argIdx = 0; argIdx < argCount; argIdx++) {
url += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]);
}
// Rename it so that our build transform doesn't attempt
// to replace this invariant() call with reactProdInvariant().
var i = invariant;
i(false,
// The error code is intentionally part of the message (and
// not the format argument) so that we could deduplicate
// different errors in logs based on the code.
'Minified React error #' + code + '; visit %s ' + 'for the full message or use the non-minified dev environment ' + 'for full errors and additional helpful warnings. ', url);
}
!React ? reactProdInvariant('227') : void 0;
var invokeGuardedCallbackImpl = function (name, func, context, a, b, c, d, e, f) {
var funcArgs = Array.prototype.slice.call(arguments, 3);
try {
func.apply(context, funcArgs);
} catch (error) {
this.onError(error);
}
};
// Used by Fiber to simulate a try-catch.
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 clearCaughtError() {
if (hasError) {
var error = caughtError;
hasError = false;
caughtError = null;
return error;
} else {
reactProdInvariant('198');
}
}
/**
* Injectable ordering of event plugins.
*/
var eventPluginOrder = null;
/**
* Injectable mapping from names to event plugin modules.
*/
var namesToPlugins = {};
/**
* Recomputes the plugin list using the injected plugins and plugin ordering.
*
* @private
*/
function recomputePluginOrdering() {
if (!eventPluginOrder) {
// Wait until an `eventPluginOrder` is injected.
return;
}
for (var pluginName in namesToPlugins) {
var pluginModule = namesToPlugins[pluginName];
var pluginIndex = eventPluginOrder.indexOf(pluginName);
!(pluginIndex > -1) ? reactProdInvariant('96', pluginName) : void 0;
if (plugins[pluginIndex]) {
continue;
}
!pluginModule.extractEvents ? reactProdInvariant('97', pluginName) : void 0;
plugins[pluginIndex] = pluginModule;
var publishedEvents = pluginModule.eventTypes;
for (var eventName in publishedEvents) {
!publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName) ? reactProdInvariant('98', eventName, pluginName) : void 0;
}
}
}
/**
* Publishes an event so that it can be dispatched by the supplied plugin.
*
* @param {object} dispatchConfig Dispatch configuration for the event.
* @param {object} PluginModule Plugin publishing the event.
* @return {boolean} True if the event was successfully published.
* @private
*/
function publishEventForPlugin(dispatchConfig, pluginModule, eventName) {
!!eventNameDispatchConfigs.hasOwnProperty(eventName) ? reactProdInvariant('99', eventName) : void 0;
eventNameDispatchConfigs[eventName] = dispatchConfig;
var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
if (phasedRegistrationNames) {
for (var phaseName in phasedRegistrationNames) {
if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
var phasedRegistrationName = phasedRegistrationNames[phaseName];
publishRegistrationName(phasedRegistrationName, pluginModule, eventName);
}
}
return true;
} else if (dispatchConfig.registrationName) {
publishRegistrationName(dispatchConfig.registrationName, pluginModule, eventName);
return true;
}
return false;
}
/**
* Publishes a registration name that is used to identify dispatched events.
*
* @param {string} registrationName Registration name to add.
* @param {object} PluginModule Plugin publishing the event.
* @private
*/
function publishRegistrationName(registrationName, pluginModule, eventName) {
!!registrationNameModules[registrationName] ? reactProdInvariant('100', registrationName) : void 0;
registrationNameModules[registrationName] = pluginModule;
registrationNameDependencies[registrationName] = pluginModule.eventTypes[eventName].dependencies;
}
/**
* Registers plugins so that they can extract and dispatch events.
*
* @see {EventPluginHub}
*/
/**
* Ordered list of injected plugins.
*/
var plugins = [];
/**
* Mapping from event name to dispatch config
*/
var eventNameDispatchConfigs = {};
/**
* Mapping from registration name to plugin module
*/
var registrationNameModules = {};
/**
* Mapping from registration name to event name
*/
var registrationNameDependencies = {};
/**
* Mapping from lowercase registration names to the properly cased version,
* used to warn in the case of missing event handlers. Available
* only in false.
* @type {Object}
*/
// Trust the developer to only use possibleRegistrationNames in false
/**
* Injects an ordering of plugins (by plugin name). This allows the ordering
* to be decoupled from injection of the actual plugins so that ordering is
* always deterministic regardless of packaging, on-the-fly injection, etc.
*
* @param {array} InjectedEventPluginOrder
* @internal
* @see {EventPluginHub.injection.injectEventPluginOrder}
*/
function injectEventPluginOrder(injectedEventPluginOrder) {
!!eventPluginOrder ? reactProdInvariant('101') : void 0;
// Clone the ordering so it cannot be dynamically mutated.
eventPluginOrder = Array.prototype.slice.call(injectedEventPluginOrder);
recomputePluginOrdering();
}
/**
* Injects plugins to be used by `EventPluginHub`. The plugin names must be
* in the ordering injected by `injectEventPluginOrder`.
*
* Plugins can be injected as part of page initialization or on-the-fly.
*
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
* @internal
* @see {EventPluginHub.injection.injectEventPluginsByName}
*/
function injectEventPluginsByName(injectedNamesToPlugins) {
var isOrderingDirty = false;
for (var pluginName in injectedNamesToPlugins) {
if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
continue;
}
var pluginModule = injectedNamesToPlugins[pluginName];
if (!namesToPlugins.hasOwnProperty(pluginName) || namesToPlugins[pluginName] !== pluginModule) {
!!namesToPlugins[pluginName] ? reactProdInvariant('102', pluginName) : void 0;
namesToPlugins[pluginName] = pluginModule;
isOrderingDirty = true;
}
}
if (isOrderingDirty) {
recomputePluginOrdering();
}
}
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
* paths. Removing the logging code for production environments will keep the
* same logic and follow the same code paths.
*/
var getFiberCurrentPropsFromNode = null;
var getInstanceFromNode = null;
var getNodeFromInstance = null;
function setComponentTree(getFiberCurrentPropsFromNodeImpl, getInstanceFromNodeImpl, getNodeFromInstanceImpl) {
getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl;
getInstanceFromNode = getInstanceFromNodeImpl;
getNodeFromInstance = getNodeFromInstanceImpl;
}
/**
* Dispatch the event to the listener.
* @param {SyntheticEvent} event SyntheticEvent to handle
* @param {function} listener Application-level callback
* @param {*} inst Internal component instance
*/
function executeDispatch(event, listener, inst) {
var type = event.type || 'unknown-event';
event.currentTarget = getNodeFromInstance(inst);
invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event);
event.currentTarget = null;
}
/**
* Standard/simple iteration through an event's collected dispatches.
*/
function executeDispatchesInOrder(event) {
var dispatchListeners = event._dispatchListeners;
var dispatchInstances = event._dispatchInstances;
if (Array.isArray(dispatchListeners)) {
for (var i = 0; i < dispatchListeners.length; i++) {
if (event.isPropagationStopped()) {
break;
}
// Listeners and Instances are two parallel arrays that are always in sync.
executeDispatch(event, dispatchListeners[i], dispatchInstances[i]);
}
} else if (dispatchListeners) {
executeDispatch(event, dispatchListeners, dispatchInstances);
}
event._dispatchListeners = null;
event._dispatchInstances = null;
}
/**
* @see executeDispatchesInOrderStopAtTrueImpl
*/
/**
* Execution of a "direct" dispatch - there must be at most one dispatch
* accumulated on the event or it is considered an error. It doesn't really make
* sense for an event with multiple dispatches (bubbled) to keep track of the
* return values at each dispatch execution, but it does tend to make sense when
* dealing with "direct" dispatches.
*
* @return {*} The return value of executing the single dispatch.
*/
/**
* @param {SyntheticEvent} event
* @return {boolean} True iff number of dispatches accumulated is greater than 0.
*/
/**
* Accumulates items that must not be null or undefined into the first one. This
* is used to conserve memory by avoiding array allocations, and thus sacrifices
* API cleanness. Since `current` can be null before being passed in and not
* null after this function, make sure to assign it back to `current`:
*
* `a = accumulateInto(a, b);`
*
* This API should be sparingly used. Try `accumulate` for something cleaner.
*
* @return {*|array<*>} An accumulation of items.
*/
function accumulateInto(current, next) {
!(next != null) ? reactProdInvariant('30') : void 0;
if (current == null) {
return next;
}
// Both are not empty. Warning: Never call x.concat(y) when you are not
// certain that x is an Array (x could be a string with concat method).
if (Array.isArray(current)) {
if (Array.isArray(next)) {
current.push.apply(current, next);
return current;
}
current.push(next);
return current;
}
if (Array.isArray(next)) {
// A bit too dangerous to mutate `next`.
return [current].concat(next);
}
return [current, next];
}
/**
* @param {array} arr an "accumulation" of items which is either an Array or
* a single item. Useful when paired with the `accumulate` module. This is a
* simple utility that allows us to reason about a collection of items, but
* handling the case when there is exactly one item (and we do not need to
* allocate an array).
* @param {function} cb Callback invoked with each element or a collection.
* @param {?} [scope] Scope used as `this` in a callback.
*/
function forEachAccumulated(arr, cb, scope) {
if (Array.isArray(arr)) {
arr.forEach(cb, scope);
} else if (arr) {
cb.call(scope, arr);
}
}
/**
* Internal queue of events that have accumulated their dispatches and are
* waiting to have their dispatches executed.
*/
var eventQueue = null;
/**
* Dispatches an event and releases it back into the pool, unless persistent.
*
* @param {?object} event Synthetic event to be dispatched.
* @private
*/
var executeDispatchesAndRelease = function (event) {
if (event) {
executeDispatchesInOrder(event);
if (!event.isPersistent()) {
event.constructor.release(event);
}
}
};
var executeDispatchesAndReleaseTopLevel = function (e) {
return executeDispatchesAndRelease(e);
};
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':
return !!(props.disabled && isInteractive(type));
default:
return false;
}
}
/**
* This is a unified interface for event plugins to be installed and configured.
*
* Event plugins can implement the following properties:
*
* `extractEvents` {function(string, DOMEventTarget, string, object): *}
* Required. When a top-level event is fired, this method is expected to
* extract synthetic events that will in turn be queued and dispatched.
*
* `eventTypes` {object}
* Optional, plugins that fire events must publish a mapping of registration
* names that are used to register listeners. Values of this mapping must
* be objects that contain `registrationName` or `phasedRegistrationNames`.
*
* `executeDispatch` {function(object, function, string)}
* Optional, allows plugins to override how an event gets dispatched. By
* default, the listener is simply invoked.
*
* Each plugin that is injected into `EventsPluginHub` is immediately operable.
*
* @public
*/
/**
* Methods for injecting dependencies.
*/
var injection = {
/**
* @param {array} InjectedEventPluginOrder
* @public
*/
injectEventPluginOrder: injectEventPluginOrder,
/**
* @param {object} injectedNamesToPlugins Map from names to plugin modules.
*/
injectEventPluginsByName: injectEventPluginsByName
};
/**
* @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 listener = void 0;
// TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
// live here; needs to be moved to a better place soon
var stateNode = inst.stateNode;
if (!stateNode) {
// Work in progress (ex: onload events in incremental mode).
return null;
}
var props = getFiberCurrentPropsFromNode(stateNode);
if (!props) {
// Work in progress.
return null;
}
listener = props[registrationName];
if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
return null;
}
!(!listener || typeof listener === 'function') ? reactProdInvariant('231', registrationName, typeof listener) : void 0;
return listener;
}
/**
* Allows registered plugins an opportunity to extract events from top-level
* native browser events.
*
* @return {*} An accumulation of synthetic events.
* @internal
*/
function extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var events = null;
for (var i = 0; i < plugins.length; i++) {
// Not every plugin in the ordering may be loaded at runtime.
var possiblePlugin = plugins[i];
if (possiblePlugin) {
var extractedEvents = possiblePlugin.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget);
if (extractedEvents) {
events = accumulateInto(events, extractedEvents);
}
}
}
return events;
}
function runEventsInBatch(events) {
if (events !== null) {
eventQueue = accumulateInto(eventQueue, events);
}
// Set `eventQueue` to null before processing it so that we can tell if more
// events get enqueued while processing.
var processingEventQueue = eventQueue;
eventQueue = null;
if (!processingEventQueue) {
return;
}
forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel);
!!eventQueue ? reactProdInvariant('95') : void 0;
// This would be a good time to rethrow if any of the event handlers threw.
rethrowCaughtError();
}
function runExtractedEventsInBatch(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var events = extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget);
runEventsInBatch(events);
}
var FunctionComponent = 0;
var ClassComponent = 1;
var IndeterminateComponent = 2; // Before we know whether it is function or class
var HostRoot = 3; // Root of a host tree. Could be nested inside another node.
var HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
var HostComponent = 5;
var HostText = 6;
var Fragment = 7;
var Mode = 8;
var ContextConsumer = 9;
var ContextProvider = 10;
var ForwardRef = 11;
var Profiler = 12;
var SuspenseComponent = 13;
var MemoComponent = 14;
var SimpleMemoComponent = 15;
var LazyComponent = 16;
var IncompleteClassComponent = 17;
var DehydratedSuspenseComponent = 18;
var randomKey = Math.random().toString(36).slice(2);
var internalInstanceKey = '__reactInternalInstance$' + randomKey;
var internalEventHandlersKey = '__reactEventHandlers$' + randomKey;
function precacheFiberNode(hostInst, node) {
node[internalInstanceKey] = hostInst;
}
/**
* Given a DOM node, return the closest ReactDOMComponent or
* ReactDOMTextComponent instance ancestor.
*/
function getClosestInstanceFromNode(node) {
if (node[internalInstanceKey]) {
return node[internalInstanceKey];
}
while (!node[internalInstanceKey]) {
if (node.parentNode) {
node = node.parentNode;
} else {
// Top of the tree. This node must not be part of a React tree (or is
// unmounted, potentially).
return null;
}
}
var inst = node[internalInstanceKey];
if (inst.tag === HostComponent || inst.tag === HostText) {
// In Fiber, this will always be the deepest root.
return inst;
}
return null;
}
/**
* Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent
* instance, or null if the node was not rendered by this React.
*/
function getInstanceFromNode$1(node) {
var inst = node[internalInstanceKey];
if (inst) {
if (inst.tag === HostComponent || inst.tag === HostText) {
return inst;
} else {
return null;
}
}
return null;
}
/**
* Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding
* DOM node.
*/
function getNodeFromInstance$1(inst) {
if (inst.tag === HostComponent || inst.tag === HostText) {
// In Fiber this, is just the state node right now. We assume it will be
// a host component or host text.
return inst.stateNode;
}
// Without this first invariant, passing a non-DOM-component triggers the next
// invariant for a missing parent, which is super confusing.
reactProdInvariant('33');
}
function getFiberCurrentPropsFromNode$1(node) {
return node[internalEventHandlersKey] || null;
}
function updateFiberProps(node, props) {
node[internalEventHandlersKey] = props;
}
function getParent(inst) {
do {
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);
if (inst) {
return inst;
}
return null;
}
/**
* Return the lowest common ancestor of A and B, or null if they are in
* different trees.
*/
function getLowestCommonAncestor(instA, instB) {
var depthA = 0;
for (var tempA = instA; tempA; tempA = getParent(tempA)) {
depthA++;
}
var depthB = 0;
for (var tempB = instB; tempB; tempB = getParent(tempB)) {
depthB++;
}
// If A is deeper, crawl up.
while (depthA - depthB > 0) {
instA = getParent(instA);
depthA--;
}
// If B is deeper, crawl up.
while (depthB - depthA > 0) {
instB = getParent(instB);
depthB--;
}
// Walk in lockstep until we find a match.
var depth = depthA;
while (depth--) {
if (instA === instB || instA === instB.alternate) {
return instA;
}
instA = getParent(instA);
instB = getParent(instB);
}
return null;
}
/**
* Return if A is an ancestor of B.
*/
/**
* Return the parent instance of the passed-in instance.
*/
/**
* Simulates the traversal of a two-phase, capture/bubble event dispatch.
*/
function traverseTwoPhase(inst, fn, arg) {
var path = [];
while (inst) {
path.push(inst);
inst = getParent(inst);
}
var i = void 0;
for (i = path.length; i-- > 0;) {
fn(path[i], 'captured', arg);
}
for (i = 0; i < path.length; i++) {
fn(path[i], 'bubbled', arg);
}
}
/**
* Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
* should would receive a `mouseEnter` or `mouseLeave` event.
*
* Does not invoke the callback on the nearest common ancestor because nothing
* "entered" or "left" that element.
*/
function traverseEnterLeave(from, to, fn, argFrom, argTo) {
var common = from && to ? getLowestCommonAncestor(from, to) : null;
var pathFrom = [];
while (true) {
if (!from) {
break;
}
if (from === common) {
break;
}
var alternate = from.alternate;
if (alternate !== null && alternate === common) {
break;
}
pathFrom.push(from);
from = getParent(from);
}
var pathTo = [];
while (true) {
if (!to) {
break;
}
if (to === common) {
break;
}
var _alternate = to.alternate;
if (_alternate !== null && _alternate === common) {
break;
}
pathTo.push(to);
to = getParent(to);
}
for (var i = 0; i < pathFrom.length; i++) {
fn(pathFrom[i], 'bubbled', argFrom);
}
for (var _i = pathTo.length; _i-- > 0;) {
fn(pathTo[_i], 'captured', argTo);
}
}
/**
* Some event types have a notion of different registration names for different
* "phases" of propagation. This finds listeners by a given phase.
*/
function listenerAtPhase(inst, event, propagationPhase) {
var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase];
return getListener(inst, registrationName);
}
/**
* A small set of propagation patterns, each of which will accept a small amount
* of information, and generate a set of "dispatch ready event objects" - which
* are sets of events that have already been annotated with a set of dispatched
* listener functions/ids. The API is designed this way to discourage these
* propagation strategies from actually executing the dispatches, since we
* always want to collect the entire set of dispatches before executing even a
* single one.
*/
/**
* Tags a `SyntheticEvent` with dispatched listeners. Creating this function
* here, allows us to not have to bind or create functions for each event.
* Mutating the event's members allows us to not have to create a wrapping
* "dispatch" object that pairs the event with the listener.
*/
function accumulateDirectionalDispatches(inst, phase, event) {
var listener = listenerAtPhase(inst, event, phase);
if (listener) {
event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
}
}
/**
* Collect dispatches (must be entirely collected before dispatching - see unit
* tests). Lazily allocate the array to conserve memory. We must loop through
* each event and perform the traversal for each one. We cannot perform a
* single traversal for the entire collection of events because each event may
* have a different target.
*/
function accumulateTwoPhaseDispatchesSingle(event) {
if (event && event.dispatchConfig.phasedRegistrationNames) {
traverseTwoPhase(event._targetInst, accumulateDirectionalDispatches, event);
}
}
/**
* Accumulates without regard to direction, does not look for phased
* registration names. Same as `accumulateDirectDispatchesSingle` but without
* requiring that the `dispatchMarker` be the same as the dispatched ID.
*/
function accumulateDispatches(inst, ignoredDirection, event) {
if (inst && event && event.dispatchConfig.registrationName) {
var registrationName = event.dispatchConfig.registrationName;
var listener = getListener(inst, registrationName);
if (listener) {
event._dispatchListeners = accumulateInto(event._dispatchListeners, listener);
event._dispatchInstances = accumulateInto(event._dispatchInstances, inst);
}
}
}
/**
* Accumulates dispatches on an `SyntheticEvent`, but only for the
* `dispatchMarker`.
* @param {SyntheticEvent} event
*/
function accumulateDirectDispatchesSingle(event) {
if (event && event.dispatchConfig.registrationName) {
accumulateDispatches(event._targetInst, null, event);
}
}
function accumulateTwoPhaseDispatches(events) {
forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
}
function accumulateEnterLeaveDispatches(leave, enter, from, to) {
traverseEnterLeave(from, to, accumulateDispatches, leave, enter);
}
function accumulateDirectDispatches(events) {
forEachAccumulated(events, accumulateDirectDispatchesSingle);
}
var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
// Do not uses the below two methods directly!
// Instead use constants exported from DOMTopLevelEventTypes in ReactDOM.
// (It is the only module that is allowed to access these methods.)
function unsafeCastStringToDOMTopLevelType(topLevelType) {
return topLevelType;
}
function unsafeCastDOMTopLevelTypeToString(topLevelType) {
return topLevelType;
}
/**
* 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;
}
/**
* 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).
*/
var prefixedEventNames = {};
/**
* Element to check for prefixes on.
*/
var style = {};
/**
* Bootstrap if a DOM exists.
*/
if (canUseDOM) {
style = document.createElementNS('http://www.w3.org/1999/xhtml', '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 (!('AnimationEvent' in window)) {
delete vendorPrefixes.animationend.animation;
delete vendorPrefixes.animationiteration.animation;
delete vendorPrefixes.animationstart.animation;
}
// Same as above
if (!('TransitionEvent' in window)) {
delete vendorPrefixes.transitionend.transition;
}
}
/**
* 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;
}
var prefixMap = vendorPrefixes[eventName];
for (var styleProp in prefixMap) {
if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) {
return prefixedEventNames[eventName] = prefixMap[styleProp];
}
}
return eventName;
}
/**
* To identify top level events in ReactDOM, we use constants defined by this
* module. This is the only module that uses the unsafe* methods to express
* that the constants actually correspond to the browser event names. This lets
* us save some bundle size by avoiding a top level type -> event name map.
* The rest of ReactDOM code should import top level types from this file.
*/
var TOP_ABORT = unsafeCastStringToDOMTopLevelType('abort');
var TOP_ANIMATION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationend'));
var TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationiteration'));
var TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('animationstart'));
var TOP_BLUR = unsafeCastStringToDOMTopLevelType('blur');
var TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay');
var TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType('canplaythrough');
var TOP_CANCEL = unsafeCastStringToDOMTopLevelType('cancel');
var TOP_CHANGE = unsafeCastStringToDOMTopLevelType('change');
var TOP_CLICK = unsafeCastStringToDOMTopLevelType('click');
var TOP_CLOSE = unsafeCastStringToDOMTopLevelType('close');
var TOP_COMPOSITION_END = unsafeCastStringToDOMTopLevelType('compositionend');
var TOP_COMPOSITION_START = unsafeCastStringToDOMTopLevelType('compositionstart');
var TOP_COMPOSITION_UPDATE = unsafeCastStringToDOMTopLevelType('compositionupdate');
var TOP_CONTEXT_MENU = unsafeCastStringToDOMTopLevelType('contextmenu');
var TOP_COPY = unsafeCastStringToDOMTopLevelType('copy');
var TOP_CUT = unsafeCastStringToDOMTopLevelType('cut');
var TOP_DOUBLE_CLICK = unsafeCastStringToDOMTopLevelType('dblclick');
var TOP_AUX_CLICK = unsafeCastStringToDOMTopLevelType('auxclick');
var TOP_DRAG = unsafeCastStringToDOMTopLevelType('drag');
var TOP_DRAG_END = unsafeCastStringToDOMTopLevelType('dragend');
var TOP_DRAG_ENTER = unsafeCastStringToDOMTopLevelType('dragenter');
var TOP_DRAG_EXIT = unsafeCastStringToDOMTopLevelType('dragexit');
var TOP_DRAG_LEAVE = unsafeCastStringToDOMTopLevelType('dragleave');
var TOP_DRAG_OVER = unsafeCastStringToDOMTopLevelType('dragover');
var TOP_DRAG_START = unsafeCastStringToDOMTopLevelType('dragstart');
var TOP_DROP = unsafeCastStringToDOMTopLevelType('drop');
var TOP_DURATION_CHANGE = unsafeCastStringToDOMTopLevelType('durationchange');
var TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied');
var TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted');
var TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended');
var TOP_ERROR = unsafeCastStringToDOMTopLevelType('error');
var TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus');
var TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('gotpointercapture');
var TOP_INPUT = unsafeCastStringToDOMTopLevelType('input');
var TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid');
var TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown');
var TOP_KEY_PRESS = unsafeCastStringToDOMTopLevelType('keypress');
var TOP_KEY_UP = unsafeCastStringToDOMTopLevelType('keyup');
var TOP_LOAD = unsafeCastStringToDOMTopLevelType('load');
var TOP_LOAD_START = unsafeCastStringToDOMTopLevelType('loadstart');
var TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata');
var TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType('loadedmetadata');
var TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType('lostpointercapture');
var TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown');
var TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove');
var TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout');
var TOP_MOUSE_OVER = unsafeCastStringToDOMTopLevelType('mouseover');
var TOP_MOUSE_UP = unsafeCastStringToDOMTopLevelType('mouseup');
var TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste');
var TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause');
var TOP_PLAY = unsafeCastStringToDOMTopLevelType('play');
var TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing');
var TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType('pointercancel');
var TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType('pointerdown');
var TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType('pointermove');
var TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout');
var TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType('pointerover');
var TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup');
var TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress');
var TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange');
var TOP_RESET = unsafeCastStringToDOMTopLevelType('reset');
var TOP_SCROLL = unsafeCastStringToDOMTopLevelType('scroll');
var TOP_SEEKED = unsafeCastStringToDOMTopLevelType('seeked');
var TOP_SEEKING = unsafeCastStringToDOMTopLevelType('seeking');
var TOP_SELECTION_CHANGE = unsafeCastStringToDOMTopLevelType('selectionchange');
var TOP_STALLED = unsafeCastStringToDOMTopLevelType('stalled');
var TOP_SUBMIT = unsafeCastStringToDOMTopLevelType('submit');
var TOP_SUSPEND = unsafeCastStringToDOMTopLevelType('suspend');
var TOP_TEXT_INPUT = unsafeCastStringToDOMTopLevelType('textInput');
var TOP_TIME_UPDATE = unsafeCastStringToDOMTopLevelType('timeupdate');
var TOP_TOGGLE = unsafeCastStringToDOMTopLevelType('toggle');
var TOP_TOUCH_CANCEL = unsafeCastStringToDOMTopLevelType('touchcancel');
var TOP_TOUCH_END = unsafeCastStringToDOMTopLevelType('touchend');
var TOP_TOUCH_MOVE = unsafeCastStringToDOMTopLevelType('touchmove');
var TOP_TOUCH_START = unsafeCastStringToDOMTopLevelType('touchstart');
var TOP_TRANSITION_END = unsafeCastStringToDOMTopLevelType(getVendorPrefixedEventName('transitionend'));
var TOP_VOLUME_CHANGE = unsafeCastStringToDOMTopLevelType('volumechange');
var TOP_WAITING = unsafeCastStringToDOMTopLevelType('waiting');
var TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel');
// List of events that need to be individually attached to media elements.
// Note that events in this list will *not* be listened to at the top level
// unless they're explicitly whitelisted in `ReactBrowserEventEmitter.listenTo`.
var mediaEventTypes = [TOP_ABORT, TOP_CAN_PLAY, TOP_CAN_PLAY_THROUGH, TOP_DURATION_CHANGE, TOP_EMPTIED, TOP_ENCRYPTED, TOP_ENDED, TOP_ERROR, TOP_LOADED_DATA, TOP_LOADED_METADATA, TOP_LOAD_START, TOP_PAUSE, TOP_PLAY, TOP_PLAYING, TOP_PROGRESS, TOP_RATE_CHANGE, TOP_SEEKED, TOP_SEEKING, TOP_STALLED, TOP_SUSPEND, TOP_TIME_UPDATE, TOP_VOLUME_CHANGE, TOP_WAITING];
function getRawEventName(topLevelType) {
return unsafeCastDOMTopLevelTypeToString(topLevelType);
}
/**
* 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;
}
var start = void 0;
var startValue = startText;
var startLength = startValue.length;
var end = void 0;
var endValue = getText();
var endLength = endValue.length;
for (start = 0; start < startLength; start++) {
if (startValue[start] !== endValue[start]) {
break;
}
}
var minEnd = startLength - start;
for (end = 1; end <= minEnd; end++) {
if (startValue[startLength - end] !== endValue[endLength - end]) {
break;
}
}
var sliceTail = end > 1 ? 1 - end : undefined;
fallbackText = endValue.slice(start, sliceTail);
return fallbackText;
}
function getText() {
if ('value' in root) {
return root.value;
}
return root.textContent;
}
var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
var _assign = ReactInternals.assign;
/* eslint valid-typeof: 0 */
var EVENT_POOL_SIZE = 10;
/**
* @interface Event
*/
var EventInterface = {
type: null,
target: null,
// currentTarget is set when dispatching; no use in copying it here
currentTarget: function () {
return null;
},
eventPhase: null,
bubbles: null,
cancelable: null,
timeStamp: function (event) {
return event.timeStamp || Date.now();
},
defaultPrevented: null,
isTrusted: null
};
function functionThatReturnsTrue() {
return true;
}
function functionThatReturnsFalse() {
return false;
}
/**
* 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.
*
* @param {object} dispatchConfig Configuration used to dispatch this event.
* @param {*} targetInst Marker identifying the event target.
* @param {object} nativeEvent Native browser event.
* @param {DOMEventTarget} nativeEventTarget Target node.
*/
function SyntheticEvent(dispatchConfig, targetInst, nativeEvent, nativeEventTarget) {
this.dispatchConfig = dispatchConfig;
this._targetInst = targetInst;
this.nativeEvent = nativeEvent;
var Interface = this.constructor.Interface;
for (var propName in Interface) {
if (!Interface.hasOwnProperty(propName)) {
continue;
}
var normalize = Interface[propName];
if (normalize) {
this[propName] = normalize(nativeEvent);
} else {
if (propName === 'target') {
this.target = nativeEventTarget;
} else {
this[propName] = nativeEvent[propName];
}
}
}
var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false;
if (defaultPrevented) {
this.isDefaultPrevented = functionThatReturnsTrue;
} else {
this.isDefaultPrevented = functionThatReturnsFalse;
}
this.isPropagationStopped = functionThatReturnsFalse;
return this;
}
_assign(SyntheticEvent.prototype, {
preventDefault: function () {
this.defaultPrevented = true;
var event = this.nativeEvent;
if (!event) {
return;
}
if (event.preventDefault) {
event.preventDefault();
} else if (typeof event.returnValue !== 'unknown') {
event.returnValue = false;
}
this.isDefaultPrevented = functionThatReturnsTrue;
},
stopPropagation: function () {
var event = this.nativeEvent;
if (!event) {
return;
}
if (event.stopPropagation) {
event.stopPropagation();
} 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;
}
this.isPropagationStopped = functionThatReturnsTrue;
},
/**
* 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 () {
this.isPersistent = functionThatReturnsTrue;
},
/**
* Checks if this event should be released back into the pool.
*
* @return {boolean} True if this should not be released, false otherwise.
*/
isPersistent: functionThatReturnsFalse,
/**
* `PooledClass` looks for `destructor` on each instance it releases.
*/
destructor: function () {
var Interface = this.constructor.Interface;
for (var propName in Interface) {
{
this[propName] = null;
}
}
this.dispatchConfig = null;
this._targetInst = null;
this.nativeEvent = null;
this.isDefaultPrevented = functionThatReturnsFalse;
this.isPropagationStopped = functionThatReturnsFalse;
this._dispatchListeners = null;
this._dispatchInstances = null;
}
});
SyntheticEvent.Interface = EventInterface;
/**
* Helper to reduce boilerplate when creating subclasses.
*/
SyntheticEvent.extend = function (Interface) {
var Super = this;
var E = function () {};
E.prototype = Super.prototype;
var prototype = new E();
function Class() {
return Super.apply(this, arguments);
}
_assign(prototype, Class.prototype);
Class.prototype = prototype;
Class.prototype.constructor = Class;
Class.Interface = _assign({}, Super.Interface, Interface);
Class.extend = Super.extend;
addEventPoolingTo(Class);
return Class;
};
addEventPoolingTo(SyntheticEvent);
function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) {
var EventConstructor = this;
if (EventConstructor.eventPool.length) {
var instance = EventConstructor.eventPool.pop();
EventConstructor.call(instance, dispatchConfig, targetInst, nativeEvent, nativeInst);
return instance;
}
return new EventConstructor(dispatchConfig, targetInst, nativeEvent, nativeInst);
}
function releasePooledEvent(event) {
var EventConstructor = this;
!(event instanceof EventConstructor) ? reactProdInvariant('279') : void 0;
event.destructor();
if (EventConstructor.eventPool.length < EVENT_POOL_SIZE) {
EventConstructor.eventPool.push(event);
}
}
function addEventPoolingTo(EventConstructor) {
EventConstructor.eventPool = [];
EventConstructor.getPooled = getPooledEvent;
EventConstructor.release = releasePooledEvent;
}
/**
* @interface Event
*/
var SyntheticCompositionEvent = SyntheticEvent.extend({
data: null
});
/**
* @interface Event
* /#events-inputevents
*/
var SyntheticInputEvent = SyntheticEvent.extend({
data: null
});
var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
var START_KEYCODE = 229;
var canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window;
var documentMode = null;
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 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 useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11);
var SPACEBAR_CODE = 32;
var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
// Events and their corresponding property names.
var eventTypes = {
beforeInput: {
phasedRegistrationNames: {
bubbled: 'onBeforeInput',
captured: 'onBeforeInputCapture'
},
dependencies: [TOP_COMPOSITION_END, TOP_KEY_PRESS, TOP_TEXT_INPUT, TOP_PASTE]
},
compositionEnd: {
phasedRegistrationNames: {
bubbled: 'onCompositionEnd',
captured: 'onCompositionEndCapture'
},
dependencies: [TOP_BLUR, TOP_COMPOSITION_END, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN]
},
compositionStart: {
phasedRegistrationNames: {
bubbled: 'onCompositionStart',
captured: 'onCompositionStartCapture'
},
dependencies: [TOP_BLUR, TOP_COMPOSITION_START, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN]
},
compositionUpdate: {
phasedRegistrationNames: {
bubbled: 'onCompositionUpdate',
captured: 'onCompositionUpdateCapture'
},
dependencies: [TOP_BLUR, TOP_COMPOSITION_UPDATE, TOP_KEY_DOWN, TOP_KEY_PRESS, TOP_KEY_UP, TOP_MOUSE_DOWN]
}
};
// 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);
}
/**
* Translate native top level events into event types.
*
* @param {string} topLevelType
* @return {object}
*/
function getCompositionEventType(topLevelType) {
switch (topLevelType) {
case TOP_COMPOSITION_START:
return eventTypes.compositionStart;
case TOP_COMPOSITION_END:
return eventTypes.compositionEnd;
case TOP_COMPOSITION_UPDATE:
return eventTypes.compositionUpdate;
}
}
/**
* Does our fallback best-guess model think this event signifies that
* composition has begun?
*
* @param {string} topLevelType
* @param {object} nativeEvent
* @return {boolean}
*/
function isFallbackCompositionStart(topLevelType, nativeEvent) {
return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE;
}
/**
* Does our fallback mode think that this event is the end of composition?
*
* @param {string} topLevelType
* @param {object} nativeEvent
* @return {boolean}
*/
function isFallbackCompositionEnd(topLevelType, nativeEvent) {
switch (topLevelType) {
case TOP_KEY_UP:
// Command keys insert or clear IME input.
return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
case TOP_KEY_DOWN:
// Expect IME keyCode on each keydown. If we get any other
// code we must have exited earlier.
return nativeEvent.keyCode !== START_KEYCODE;
case TOP_KEY_PRESS:
case TOP_MOUSE_DOWN:
case TOP_BLUR:
// Events are not possible without cancelling IME.
return true;
default:
return false;
}
}
/**
* 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;
}
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 extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var eventType = void 0;
var fallbackData = void 0;
if (canUseCompositionEvent) {
eventType = getCompositionEventType(topLevelType);
} else if (!isComposing) {
if (isFallbackCompositionStart(topLevelType, nativeEvent)) {
eventType = eventTypes.compositionStart;
}
} else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) {
eventType = eventTypes.compositionEnd;
}
if (!eventType) {
return null;
}
if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) {
// The current composition is stored statically and must not be
// overwritten while composition continues.
if (!isComposing && eventType === eventTypes.compositionStart) {
isComposing = initialize(nativeEventTarget);
} else if (eventType === eventTypes.compositionEnd) {
if (isComposing) {
fallbackData = getData();
}
}
}
var event = SyntheticCompositionEvent.getPooled(eventType, targetInst, nativeEvent, nativeEventTarget);
if (fallbackData) {
// Inject data generated from fallback path into the synthetic event.
// This matches the property of native CompositionEventInterface.
event.data = fallbackData;
} else {
var customData = getDataFromCustomEvent(nativeEvent);
if (customData !== null) {
event.data = customData;
}
}
accumulateTwoPhaseDispatches(event);
return event;
}
/**
* @param {TopLevelType} topLevelType Number from `TopLevelType`.
* @param {object} nativeEvent Native browser event.
* @return {?string} The string corresponding to this `beforeInput` event.
*/
function getNativeBeforeInputChars(topLevelType, nativeEvent) {
switch (topLevelType) {
case TOP_COMPOSITION_END:
return getDataFromCustomEvent(nativeEvent);
case TOP_KEY_PRESS:
/**
* 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:
*
* To avoid this issue, use the keypress event as if no `textInput`
* event is available.
*/
var which = nativeEvent.which;
if (which !== SPACEBAR_CODE) {
return null;
}
hasSpaceKeypress = true;
return SPACEBAR_CHAR;
case TOP_TEXT_INPUT:
// 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;
}
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.
*
* @param {number} topLevelType Number from `TopLevelEventTypes`.
* @param {object} nativeEvent Native browser event.
* @return {?string} The fallback string for this `beforeInput` event.
*/
function getFallbackBeforeInputChars(topLevelType, 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 (topLevelType === TOP_COMPOSITION_END || !canUseCompositionEvent && isFallbackCompositionEnd(topLevelType, nativeEvent)) {
var chars = getData();
reset();
isComposing = false;
return chars;
}
return null;
}
switch (topLevelType) {
case TOP_PASTE:
// If a paste event occurs after a keypress, throw out the input
// chars. Paste events should not lead to BeforeInput events.
return null;
case TOP_KEY_PRESS:
/**
* 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);
}
}
return null;
case TOP_COMPOSITION_END:
return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data;
default:
return null;
}
}
/**
* Extract a SyntheticInputEvent for `beforeInput`, based on either native
* `textInput` or fallback behavior.
*
* @return {?object} A SyntheticInputEvent.
*/
function extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var chars = void 0;
if (canUseTextInputEvent) {
chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
} else {
chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
}
// If no characters are being inserted, no BeforeInput event should
// be fired.
if (!chars) {
return null;
}
var event = SyntheticInputEvent.getPooled(eventTypes.beforeInput, targetInst, nativeEvent, nativeEventTarget);
event.data = chars;
accumulateTwoPhaseDispatches(event);
return event;
}
/**
* Create an `onBeforeInput` event to match
*
* 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.
*/
var BeforeInputEventPlugin = {
eventTypes: eventTypes,
extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var composition = extractCompositionEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget);
var beforeInput = extractBeforeInputEvent(topLevelType, targetInst, nativeEvent, nativeEventTarget);
if (composition === null) {
return beforeInput;
}
if (beforeInput === null) {
return composition;
}
return [composition, beforeInput];
}
};
// Use to restore controlled state after a change event has fired.
var restoreImpl = null;
var restoreTarget = null;
var restoreQueue = null;
function restoreStateOfTarget(target) {
// We perform this translation at the end of the event loop so that we
// always receive the correct fiber here
var internalInstance = getInstanceFromNode(target);
if (!internalInstance) {
// Unmounted
return;
}
!(typeof restoreImpl === 'function') ? reactProdInvariant('280') : void 0;
var props = getFiberCurrentPropsFromNode(internalInstance.stateNode);
restoreImpl(internalInstance.stateNode, internalInstance.type, props);
}
function setRestoreImplementation(impl) {
restoreImpl = impl;
}
function enqueueStateRestore(target) {
if (restoreTarget) {
if (restoreQueue) {
restoreQueue.push(target);
} else {
restoreQueue = [target];
}
} else {
restoreTarget = target;
}
}
function needsStateRestore() {
return restoreTarget !== null || restoreQueue !== null;
}
function restoreStateIfNeeded() {
if (!restoreTarget) {
return;
}
var target = restoreTarget;
var queuedTargets = restoreQueue;
restoreTarget = null;
restoreQueue = null;
restoreStateOfTarget(target);
if (queuedTargets) {
for (var i = 0; i < queuedTargets.length; i++) {
restoreStateOfTarget(queuedTargets[i]);
}
}
}
// Used as a way to call batchedUpdates when we don't have a reference to
// 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 _interactiveUpdatesImpl = function (fn, a, b) {
return fn(a, b);
};
var _flushInteractiveUpdatesImpl = function () {};
var isBatching = false;
function batchedUpdates(fn, bookkeeping) {
if (isBatching) {
// If we are currently inside another batch, we need to wait until it
// fully completes before restoring state.
return fn(bookkeeping);
}
isBatching = true;
try {
return _batchedUpdatesImpl(fn, bookkeeping);
} finally {
// Here we wait until all updates have propagated, which is important
// when using controlled components within layers:
// Then we restore state of any controlled component.
isBatching = false;
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.
_flushInteractiveUpdatesImpl();
restoreStateIfNeeded();
}
}
}
function interactiveUpdates(fn, a, b) {
return _interactiveUpdatesImpl(fn, a, b);
}
function setBatchingImplementation(batchedUpdatesImpl, interactiveUpdatesImpl, flushInteractiveUpdatesImpl) {
_batchedUpdatesImpl = batchedUpdatesImpl;
_interactiveUpdatesImpl = interactiveUpdatesImpl;
_flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl;
}
/**
*/
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();
if (nodeName === 'input') {
return !!supportedInputTypes[elem.type];
}
if (nodeName === 'textarea') {
return true;
}
return false;
}
/**
* HTML nodeType values that represent the type of the node
*/
var ELEMENT_NODE = 1;
var TEXT_NODE = 3;
var COMMENT_NODE = 8;
var DOCUMENT_NODE = 9;
var DOCUMENT_FRAGMENT_NODE = 11;
/**
* Gets the target node from a native browser event by accounting for
* inconsistencies in browser DOM APIs.
*
* @param {object} nativeEvent Native browser event.
* @return {DOMEventTarget} Target node.
*/
function getEventTarget(nativeEvent) {
// Fallback to nativeEvent.srcElement for IE9
var target = nativeEvent.target || nativeEvent.srcElement || window;
// Normalize SVG <use> element events #4963
if (target.correspondingUseElement) {
target = target.correspondingUseElement;
}
// Safari may fire events on text nodes (Node.TEXT_NODE is 3).
return target.nodeType === TEXT_NODE ? target.parentNode : target;
}
/**
* 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;
}
var eventName = 'on' + eventNameSuffix;
var isSupported = eventName in document;
if (!isSupported) {
var element = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
element.setAttribute(eventName, 'return;');
isSupported = typeof element[eventName] === 'function';
}
return isSupported;
}
function isCheckable(elem) {
var type = elem.type;
var nodeName = elem.nodeName;
return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio');
}
function getTracker(node) {
return node._valueTracker;
}
function detachTracker(node) {
node._valueTracker = null;
}
function getValueFromNode(node) {
var value = '';
if (!node) {
return value;
}
if (isCheckable(node)) {
value = node.checked ? 'true' : 'false';
} else {
value = node.value;
}
return value;
}
function trackValueOnNode(node) {
var valueField = isCheckable(node) ? 'checked' : 'value';
var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField);
var currentValue = '' + node[valueField];
// if someone has already defined a value or Safari, then bail
// and don't track value will cause over reporting of changes,
// but it's better then a hard failure
// (needed for certain tests that spyOn input values and Safari)
if (node.hasOwnProperty(valueField) || typeof descriptor === 'undefined' || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') {
return;
}
var get = descriptor.get,
set = descriptor.set;
Object.defineProperty(node, valueField, {
configurable: true,
get: function () {
return get.call(this);
},
set: function (value) {
currentValue = '' + value;
set.call(this, value);
}
});
// We could've passed this the first time
// but it triggers a bug in IE11 and Edge 14/15.
// Calling defineProperty() again should be equivalent.
Object.defineProperty(node, valueField, {
enumerable: descriptor.enumerable
});
var tracker = {
getValue: function () {
return currentValue;
},
setValue: function (value) {
currentValue = '' + value;
},
stopTracking: function () {
detachTracker(node);
delete node[valueField];
}
};
return tracker;
}
function track(node) {
if (getTracker(node)) {
return;
}
// TODO: Once it's just Fiber we can move this to node._wrapperState
node._valueTracker = trackValueOnNode(node);
}
function updateValueIfChanged(node) {
if (!node) {
return false;
}
var tracker = getTracker(node);
// if there is no tracker at this point it's unlikely
// that trying again will succeed
if (!tracker) {
return true;
}
var lastValue = tracker.getValue();
var nextValue = getValueFromNode(node);
if (nextValue !== lastValue) {
tracker.setValue(nextValue);
return true;
}
return false;
}
var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
// Prevent newer renderers from RTE when used with older react package versions.
// Current owner and dispatcher used to share the same ref,
// but PR #14548 split them out to better support the react-debug-tools package.
if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) {
ReactSharedInternals.ReactCurrentDispatcher = {
current: null
};
}
var BEFORE_SLASH_RE = /^(.*)[\\\/]/;
var describeComponentFrame = function (name, source, ownerName) {
var sourceInfo = '';
if (source) {
var path = source.fileName;
var fileName = path.replace(BEFORE_SLASH_RE, '');
sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')';
} else if (ownerName) {
sourceInfo = ' (created by ' + ownerName + ')';
}
return '\n in ' + (name || 'Unknown') + sourceInfo;
};
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === 'function' && Symbol.for;
var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7;
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;
var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc;
var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2;
var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd;
var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace;
var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf;
var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1;
var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator';
function getIteratorFn(maybeIterable) {
if (maybeIterable === null || typeof maybeIterable !== 'object') {
return null;
}
var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
if (typeof maybeIterator === 'function') {
return maybeIterator;
}
return null;
}
var Pending = 0;
var Resolved = 1;
var Rejected = 2;
function refineResolvedLazyComponent(lazyComponent) {
return lazyComponent._status === Resolved ? lazyComponent._result : null;
}
function getWrappedName(outerType, innerType, wrapperName) {
var functionName = innerType.displayName || innerType.name || '';
return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName);
}
function getComponentName(type) {
if (type == null) {
// Host root, text node or just invalid type.
return null;
}
if (typeof type === 'function') {
return type.displayName || type.name || null;
}
if (typeof type === 'string') {
return type;
}
switch (type) {
case REACT_CONCURRENT_MODE_TYPE:
return 'ConcurrentMode';
case REACT_FRAGMENT_TYPE:
return 'Fragment';
case REACT_PORTAL_TYPE:
return 'Portal';
case REACT_PROFILER_TYPE:
return 'Profiler';
case REACT_STRICT_MODE_TYPE:
return 'StrictMode';
case REACT_SUSPENSE_TYPE:
return 'Suspense';
}
if (typeof type === 'object') {
switch (type.$$typeof) {
case REACT_CONTEXT_TYPE:
return 'Context.Consumer';
case REACT_PROVIDER_TYPE:
return 'Context.Provider';
case REACT_FORWARD_REF_TYPE:
return getWrappedName(type, type.render, 'ForwardRef');
case REACT_MEMO_TYPE:
return getComponentName(type.type);
case REACT_LAZY_TYPE:
{
var thenable = type;
var resolvedThenable = refineResolvedLazyComponent(thenable);
if (resolvedThenable) {
return getComponentName(resolvedThenable);
}
}
}
}
return null;
}
var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;
function describeFiber(fiber) {
switch (fiber.tag) {
case HostRoot:
case HostPortal:
case HostText:
case Fragment:
case ContextProvider:
case ContextConsumer:
return '';
default:
var owner = fiber._debugOwner;
var source = fiber._debugSource;
var name = getComponentName(fiber.type);
var ownerName = null;
if (owner) {
ownerName = getComponentName(owner.type);
}
return describeComponentFrame(name, source, ownerName);
}
}
function getStackByFiberInDevAndProd(workInProgress) {
var info = '';
var node = workInProgress;
do {
info += describeFiber(node);
node = node.return;
} while (node);
return info;
}
// A reserved attribute.
// It is handled by React separately and shouldn't be written to the DOM.
var RESERVED = 0;
// A simple string attribute.
// Attributes that aren't in the whitelist are presumed to have this type.
var STRING = 1;
// A string attribute that accepts booleans in React. In HTML, these are called
// "enumerated" attributes with "true" and "false" as possible values.
// When true, it should be set to a "true" string.
// When false, it should be set to a "false" string.
var BOOLEANISH_STRING = 2;
// A real boolean attribute.
// When true, it should be present (set either to an empty string or its name).
// When false, it should be omitted.
var BOOLEAN = 3;
// An attribute that can be used as a flag as well as with a value.
// When true, it should be present (set either to an empty string or its name).
// When false, it should be omitted.
// For any other value, should be present with that value.
var OVERLOADED_BOOLEAN = 4;
// An attribute that must be numeric or parse as a numeric.
// When falsy, it should be removed.
var NUMERIC = 5;
// An attribute that must be positive numeric or parse as a positive numeric.
// When falsy, it should be removed.
var POSITIVE_NUMERIC = 6;
/* eslint-disable max-len */
var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
/* eslint-enable max-len */
var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040';
var ROOT_ATTRIBUTE_NAME = 'data-reactroot';
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$');
var hasOwnProperty = Object.prototype.hasOwnProperty;
var illegalAttributeNameCache = {};
var validatedAttributeNameCache = {};
function isAttributeNameSafe(attributeName) {
if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) {
return true;
}
if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) {
return false;
}
if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) {
validatedAttributeNameCache[attributeName] = true;
return true;
}
illegalAttributeNameCache[attributeName] = true;
return false;
}
function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) {
if (propertyInfo !== null) {
return propertyInfo.type === RESERVED;
}
if (isCustomComponentTag) {
return false;
}
if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {
return true;
}
return false;
}
function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) {
if (propertyInfo !== null && propertyInfo.type === RESERVED) {
return false;
}
switch (typeof value) {
case 'function':
// $FlowIssue symbol is perfectly valid here
case 'symbol':
// eslint-disable-line
return true;
case 'boolean':
{
if (isCustomComponentTag) {
return false;
}
if (propertyInfo !== null) {
return !propertyInfo.acceptsBooleans;
} else {
var prefix = name.toLowerCase().slice(0, 5);
return prefix !== 'data-' && prefix !== 'aria-';
}
}
default:
return false;
}
}
function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) {
if (value === null || typeof value === 'undefined') {
return true;
}
if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) {
return true;
}
if (isCustomComponentTag) {
return false;
}
if (propertyInfo !== null) {
switch (propertyInfo.type) {
case BOOLEAN:
return !value;
case OVERLOADED_BOOLEAN:
return value === false;
case NUMERIC:
return isNaN(value);
case POSITIVE_NUMERIC:
return isNaN(value) || value < 1;
}
}
return false;
}
function getPropertyInfo(name) {
return properties.hasOwnProperty(name) ? properties[name] : null;
}
function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace) {
this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN;
this.attributeName = attributeName;
this.attributeNamespace = attributeNamespace;
this.mustUseProperty = mustUseProperty;
this.propertyName = name;
this.type = type;
}
// When adding attributes to this list, be sure to also add them to
// the `possibleStandardNames` module to ensure casing and incorrect
// name warnings.
var properties = {};
// These props are reserved by React. They shouldn't be written to the DOM.
['children', 'dangerouslySetInnerHTML',
// TODO: This prevents the assignment of defaultValue to regular
// elements (not just inputs). Now that ReactDOMInput assigns to the
// defaultValue property -- do we need this?
'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty
name, // attributeName
null);
} // attributeNamespace
);
// A few React string attributes have a different name.
// This is a mapping from React prop names to the attribute names.
[['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) {
var name = _ref[0],
attributeName = _ref[1];
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
attributeName, // attributeName
null);
} // attributeNamespace
);
// These are "enumerated" HTML attributes that accept "true" and "false".
// In React, we let users pass `true` and `false` even though technically
// these aren't boolean attributes (they are coerced to strings).
['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty
name.toLowerCase(), // attributeName
null);
} // attributeNamespace
);
// These are "enumerated" SVG attributes that accept "true" and "false".
// In React, we let users pass `true` and `false` even though technically
// these aren't boolean attributes (they are coerced to strings).
// Since these are SVG attributes, their attribute names are case-sensitive.
['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty
name, // attributeName
null);
} // attributeNamespace
);
// These are HTML boolean attributes.
['allowFullScreen', 'async',
// Note: there is a special case that prevents it from being written to the DOM
// on the client side because the browsers are inconsistent. Instead we call focus().
'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless',
// Microdata
'itemScope'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty
name.toLowerCase(), // attributeName
null);
} // attributeNamespace
);
// These are the few React props that we set as DOM properties
// rather than attributes. These are all booleans.
['checked',
// Note: `option.selected` is not updated if `select.multiple` is
// disabled with `removeAttribute`. We have special logic for handling this.
'multiple', 'muted', 'selected'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty
name, // attributeName
null);
} // attributeNamespace
);
// These are HTML attributes that are "overloaded booleans": they behave like
// booleans, but can also accept a string value.
['capture', 'download'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty
name, // attributeName
null);
} // attributeNamespace
);
// These are HTML attributes that must be positive numbers.
['cols', 'rows', 'size', 'span'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty
name, // attributeName
null);
} // attributeNamespace
);
// These are HTML attributes that must be numbers.
['rowSpan', 'start'].forEach(function (name) {
properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty
name.toLowerCase(), // attributeName
null);
} // attributeNamespace
);
var CAMELIZE = /[\-\:]([a-z])/g;
var capitalize = function (token) {
return token[1].toUpperCase();
};
// This is a list of all SVG attributes that need special casing, namespacing,
// or boolean value assignment. Regular attributes that just accept strings
// and have the same names are omitted, just like in the HTML whitelist.
// Some of these attributes can be hard to find. This list was created by
// scrapping the MDN documentation.
['accent-height', 'alignment-baseline', 'arabic-form', 'baseline-shift', 'cap-height', 'clip-path', 'clip-rule', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'dominant-baseline', 'enable-background', 'fill-opacity', 'fill-rule', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-name', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'horiz-adv-x', 'horiz-origin-x', 'image-rendering', 'letter-spacing', 'lighting-color', 'marker-end', 'marker-mid', 'marker-start', 'overline-position', 'overline-thickness', 'paint-order', 'panose-1', 'pointer-events', 'rendering-intent', 'shape-rendering', 'stop-color', 'stop-opacity', 'strikethrough-position', 'strikethrough-thickness', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-decoration', 'text-rendering', 'underline-position', 'underline-thickness', 'unicode-bidi', 'unicode-range', 'units-per-em', 'v-alphabetic', 'v-hanging', 'v-ideographic', 'v-mathematical', 'vector-effect', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'word-spacing', 'writing-mode', 'xmlns:xlink', 'x-height'].forEach(function (attributeName) {
var name = attributeName.replace(CAMELIZE, capitalize);
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
attributeName, null);
} // attributeNamespace
);
// String SVG attributes with the xlink namespace.
['xlink:actuate', 'xlink:arcrole', 'xlink:href', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type'].forEach(function (attributeName) {
var name = attributeName.replace(CAMELIZE, capitalize);
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
attributeName, 'http://www.w3.org/1999/xlink');
});
// String SVG attributes with the xml namespace.
['xml:base', 'xml:lang', 'xml:space'].forEach(function (attributeName) {
var name = attributeName.replace(CAMELIZE, capitalize);
properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty
});
// These attribute exists both in HTML and SVG.
// The attribute name is case-sensitive in SVG so we can't just use
// the React name like we do for attributes that exist only in HTML.
['tabIndex', 'crossOrigin'].forEach(function (attributeName) {
properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty
attributeName.toLowerCase(), // attributeName
null);
} // attributeNamespace
);
/**
* Get the value for a property on a node. Only used in DEV for SSR validation.
* The "expected" argument is used as a hint of what the expected value is.
* Some properties have multiple equivalent values.
*/
/**
* Get the value for a attribute on a node. Only used in DEV for SSR validation.
* The third argument is used as a hint of what the expected value is. Some
* attributes have multiple equivalent values.
*/
/**
* Sets the value for a property on a node.
*
* @param {DOMElement} node
* @param {string} name
* @param {*} value
*/
function setValueForProperty(node, name, value, isCustomComponentTag) {
var propertyInfo = getPropertyInfo(name);
if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) {
return;
}
if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) {
value = null;
}
// If the prop isn't in the special list, treat it as a simple attribute.
if (isCustomComponentTag || propertyInfo === null) {
if (isAttributeNameSafe(name)) {
var _attributeName = name;
if (value === null) {
node.removeAttribute(_attributeName);
} else {
node.setAttribute(_attributeName, '' + value);
}
}
return;
}
var mustUseProperty = propertyInfo.mustUseProperty;
if (mustUseProperty) {
var propertyName = propertyInfo.propertyName;
if (value === null) {
var type = propertyInfo.type;
node[propertyName] = type === BOOLEAN ? false : '';
} else {
// Contrary to `setAttribute`, object properties are properly
// `toString`ed by IE8/9.
node[propertyName] = value;
}
return;
}
// The rest are treated as attributes with special cases.
var attributeName = propertyInfo.attributeName,
attributeNamespace = propertyInfo.attributeNamespace;
if (value === null) {
node.removeAttribute(attributeName);
} else {
var _type = propertyInfo.type;
var attributeValue = void 0;
if (_type === BOOLEAN || _type === OVERLOADED_BOOLEAN && value === true) {
attributeValue = '';
} else {
// `setAttribute` with objects becomes only `[object]` in IE8/9,
// ('' + value) makes it output the correct toString()-value.
attributeValue = '' + value;
}
if (attributeNamespace) {
node.setAttributeNS(attributeNamespace, attributeName, attributeValue);
} else {
node.setAttribute(attributeName, attributeValue);
}
}
}
// Flow does not allow string concatenation of most non-string types. To work
// around this limitation, we use an opaque type that can only be obtained by
// passing the value through getToStringValue first.
function toString(value) {
return '' + value;
}
function getToStringValue(value) {
switch (typeof value) {
case 'boolean':
case 'number':
case 'object':
case 'string':
case 'undefined':
return value;
default:
// function, symbol are assigned as empty strings
return '';
}
}
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var enableUserTimingAPI = false;
// Helps identify side effects in begin-phase lifecycle hooks and setState reducers:
// In some cases, StrictMode should also double-render lifecycles.
// This can be confusing for tests though,
// And it can be bad for performance in production.
// This feature flag can be used to control the behavior:
// To preserve the "Pause on caught exceptions" behavior of the debugger, we
// replay the begin phase of a failed component inside invokeGuardedCallback.
// Warn about deprecated, async-unsafe lifecycles; relates to RFC #6:
// Gather advanced timing metrics for Profiler subtrees.
var enableProfilerTimer = false;
// Trace which interactions trigger each commit.
var enableSchedulerTracing = false;
// Only used in www builds.
var enableSuspenseServerRenderer = false; // TODO: false? Here it might just be false.
// Only used in www builds.
// Only used in www builds.
// React Fire: prevent the value and checked attributes from syncing
// with their related DOM properties
var disableInputAttributeSyncing = false;
// These APIs will no longer be "unstable" in the upcoming 16.7 release,
// Control this behavior with a flag to support 16.6 minor releases in the meanwhile.
var enableStableConcurrentModeAPIs = false;
// TODO: direct imports like some-package/src/* are bad. Fix me.
function isControlled(props) {
var usesChecked = props.type === 'checkbox' || props.type === 'radio';
return usesChecked ? props.checked != null : props.value != null;
}
/**
* Implements an <input> host component that allows setting these optional
* props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
*
* If `checked` or `value` are not supplied (or null/undefined), user actions
* that affect the checked state or value will trigger updates to the element.
*
* If they are supplied (and not null/undefined), the rendered element will not
* trigger updates to the element. Instead, the props must change in order for
* the rendered element to be updated.
*
* The rendered element will be initialized as unchecked (or `defaultChecked`)
* with an empty value (or `defaultValue`).
*
*/
function getHostProps(element, props) {
var node = element;
var checked = props.checked;
var hostProps = _assign({}, props, {
defaultChecked: undefined,
defaultValue: undefined,
value: undefined,
checked: checked != null ? checked : node._wrapperState.initialChecked
});
return hostProps;
}
function initWrapperState(element, props) {
var node = element;
var defaultValue = props.defaultValue == null ? '' : props.defaultValue;
node._wrapperState = {
initialChecked: props.checked != null ? props.checked : props.defaultChecked,
initialValue: getToStringValue(props.value != null ? props.value : defaultValue),
controlled: isControlled(props)
};
}
function updateChecked(element, props) {
var node = element;
var checked = props.checked;
if (checked != null) {
setValueForProperty(node, 'checked', checked, false);
}
}
function updateWrapper(element, props) {
var node = element;
updateChecked(element, props);
var value = getToStringValue(props.value);
var type = props.type;
if (value != null) {
if (type === 'number') {
if (value === 0 && node.value === '' ||
// We explicitly want to coerce to number here if possible.
// eslint-disable-next-line
node.value != value) {
node.value = toString(value);
}
} else if (node.value !== toString(value)) {
node.value = toString(value);
}
} else if (type === 'submit' || type === 'reset') {
// Submit/reset inputs need the attribute removed completely to avoid
// blank-text buttons.
node.removeAttribute('value');
return;
}
if (disableInputAttributeSyncing) {
// When not syncing the value attribute, React only assigns a new value
// whenever the defaultValue React prop has changed. When not present,
// React does nothing
if (props.hasOwnProperty('defaultValue')) {
setDefaultValue(node, props.type, getToStringValue(props.defaultValue));
}
} else {
// When syncing the value attribute, the value comes from a cascade of
// properties:
// 1. The value React property
// 2. The defaultValue React property
// 3. Otherwise there should be no change
if (props.hasOwnProperty('value')) {
setDefaultValue(node, props.type, value);
} else if (props.hasOwnProperty('defaultValue')) {
setDefaultValue(node, props.type, getToStringValue(props.defaultValue));
}
}
if (disableInputAttributeSyncing) {
// When not syncing the checked attribute, the attribute is directly
// controllable from the defaultValue React property. It needs to be
// updated as new props come in.
if (props.defaultChecked == null) {
node.removeAttribute('checked');
} else {
node.defaultChecked = !!props.defaultChecked;
}
} else {
// When syncing the checked attribute, it only changes when it needs
// to be removed, such as transitioning from a checkbox into a text input
if (props.checked == null && props.defaultChecked != null) {
node.defaultChecked = !!props.defaultChecked;
}
}
}
function postMountWrapper(element, props, isHydrating) {
var node = element;
// Do not assign value if it is already set. This prevents user text input
// from being lost during SSR hydration.
if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) {
var type = props.type;
var isButton = type === 'submit' || type === 'reset';
// Avoid setting value attribute on submit/reset inputs as it overrides the
// default value provided by the browser. See: #12872
if (isButton && (props.value === undefined || props.value === null)) {
return;
}
var _initialValue = toString(node._wrapperState.initialValue);
// Do not assign value if it is already set. This prevents user text input
// from being lost during SSR hydration.
if (!isHydrating) {
if (disableInputAttributeSyncing) {
var value = getToStringValue(props.value);
// When not syncing the value attribute, the value property points
// directly to the React prop. Only assign it if it exists.
if (value != null) {
// Always assign on buttons so that it is possible to assign an
// empty string to clear button text.
//
// Otherwise, do not re-assign the value property if is empty. This
// potentially avoids a DOM write and prevents Firefox (~60.0.1) from
// prematurely marking required inputs as invalid. Equality is compared
// to the current value in case the browser provided value is not an
// empty string.
if (isButton || value !== node.value) {
node.value = toString(value);
}
}
} else {
// When syncing the value attribute, the value property should use
// the wrapperState._initialValue property. This uses:
//
// 1. The value React property when present
// 2. The defaultValue React property when present
// 3. An empty string
if (_initialValue !== node.value) {
node.value = _initialValue;
}
}
}
if (disableInputAttributeSyncing) {
// When not syncing the value attribute, assign the value attribute
// directly from the defaultValue React property (when present)
var defaultValue = getToStringValue(props.defaultValue);
if (defaultValue != null) {
node.defaultValue = toString(defaultValue);
}
} else {
// Otherwise, the value attribute is synchronized to the property,
// so we assign defaultValue to the same thing as the value property
// assignment step above.
node.defaultValue = _initialValue;
}
}
// Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug
// this is needed to work around a chrome bug where setting defaultChecked
// will sometimes influence the value of checked (even after detachment).
// We need to temporarily unset name to avoid disrupting radio button groups.
var name = node.name;
if (name !== '') {
node.name = '';
}
if (disableInputAttributeSyncing) {
// When not syncing the checked attribute, the checked property
// never gets assigned. It must be manually set. We don't want
// to do this when hydrating so that existing user input isn't
// modified
if (!isHydrating) {
updateChecked(element, props);
}
// Only assign the checked attribute if it is defined. This saves
// a DOM write when controlling the checked attribute isn't needed
// (text inputs, submit/reset)
if (props.hasOwnProperty('defaultChecked')) {
node.defaultChecked = !node.defaultChecked;
node.defaultChecked = !!props.defaultChecked;
}
} else {
// When syncing the checked attribute, both the checked property and
// attribute are assigned at the same time using defaultChecked. This uses:
//
// 1. The checked React property when present
// 2. The defaultChecked React property when present
// 3. Otherwise, false
node.defaultChecked = !node.defaultChecked;
node.defaultChecked = !!node._wrapperState.initialChecked;
}
if (name !== '') {
node.name = name;
}
}
function restoreControlledState(element, props) {
var node = element;
updateWrapper(node, props);
updateNamedCousins(node, props);
}
function updateNamedCousins(rootNode, props) {
var name = props.name;
if (props.type === 'radio' && name != null) {
var queryRoot = rootNode;
while (queryRoot.parentNode) {
queryRoot = queryRoot.parentNode;
}
// If `rootNode.form` was non-null, then we could try `form.elements`,
// but that sometimes behaves strangely in IE8. We could also try using
// `form.getElementsByName`, but that will only return direct children
// and won't include inputs that use the HTML5 `form=` attribute. Since
// the input might not even be in a form. It might not even be in the
// document. Let's just use the local `querySelectorAll` to ensure we don't
// miss anything.
var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type="radio"]');
for (var i = 0; i < group.length; i++) {
var otherNode = group[i];
if (otherNode === rootNode || otherNode.form !== rootNode.form) {
continue;
}
// This will throw if radio buttons rendered by different copies of React
// and the same name are rendered into the same form (same as #1939).
// That's probably okay; we don't support it just as we don't support
// mixing React radio buttons with non-React ones.
var otherProps = getFiberCurrentPropsFromNode$1(otherNode);
!otherProps ? reactProdInvariant('90') : void 0;
// We need update the tracked value on the named cousin since the value
// was changed but the input saw no event or value set
updateValueIfChanged(otherNode);
// If this is a controlled radio button group, forcing the input that
// was previously checked to update will cause it to be come re-checked
// as appropriate.
updateWrapper(otherNode, otherProps);
}
}
}
// In Chrome, assigning defaultValue to certain input types triggers input validation.
// For number inputs, the display value loses trailing decimal points. For email inputs,
// Chrome raises "The specified value <x> is not a valid email address".
//
// Here we check to see if the defaultValue has actually changed, avoiding these problems
// when the user is inputting text
//
function setDefaultValue(node, type, value) {
if (
// Focused number inputs synchronize on blur. See ChangeEventPlugin.js
type !== 'number' || node.ownerDocument.activeElement !== node) {
if (value == null) {
node.defaultValue = toString(node._wrapperState.initialValue);
} else if (node.defaultValue !== toString(value)) {
node.defaultValue = toString(value);
}
}
}
var eventTypes$1 = {
change: {
phasedRegistrationNames: {
bubbled: 'onChange',
captured: 'onChangeCapture'
},
dependencies: [TOP_BLUR, TOP_CHANGE, TOP_CLICK, TOP_FOCUS, TOP_INPUT, TOP_KEY_DOWN, TOP_KEY_UP, TOP_SELECTION_CHANGE]
}
};
function createAndAccumulateChangeEvent(inst, nativeEvent, target) {
var event = SyntheticEvent.getPooled(eventTypes$1.change, inst, nativeEvent, target);
event.type = 'change';
// Flag this event loop as needing state restore.
enqueueStateRestore(target);
accumulateTwoPhaseDispatches(event);
return event;
}
/**
* For IE shims
*/
var activeElement = null;
var activeElementInst = null;
/**
* SECTION: handle `change` event
*/
function shouldUseChangeEvent(elem) {
var nodeName = elem.nodeName && elem.nodeName.toLowerCase();
return nodeName === 'select' || nodeName === 'input' && elem.type === 'file';
}
function manualDispatchChangeEvent(nativeEvent) {
var event = createAndAccumulateChangeEvent(activeElementInst, 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
batchedUpdates(runEventInBatch, event);
}
function runEventInBatch(event) {
runEventsInBatch(event);
}
function getInstIfValueChanged(targetInst) {
var targetNode = getNodeFromInstance$1(targetInst);
if (updateValueIfChanged(targetNode)) {
return targetInst;
}
}
function getTargetInstForChangeEvent(topLevelType, targetInst) {
if (topLevelType === TOP_CHANGE) {
return targetInst;
}
}
/**
* SECTION: handle `input` event
*/
var isInputEventSupported = false;
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.
*/
function startWatchingForValueChange(target, targetInst) {
activeElement = target;
activeElementInst = targetInst;
activeElement.attachEvent('onpropertychange', handlePropertyChange);
}
/**
* (For IE <=9) Removes the event listeners from the currently-tracked element,
* if any exists.
*/
function stopWatchingForValueChange() {
if (!activeElement) {
return;
}
activeElement.detachEvent('onpropertychange', handlePropertyChange);
activeElement = null;
activeElementInst = null;
}
/**
* (For IE <=9) Handles a propertychange event, sending a `change` event if
* the value of the active element has changed.
*/
function handlePropertyChange(nativeEvent) {
if (nativeEvent.propertyName !== 'value') {
return;
}
if (getInstIfValueChanged(activeElementInst)) {
manualDispatchChangeEvent(nativeEvent);
}
}
function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
if (topLevelType === TOP_FOCUS) {
// 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 (topLevelType === TOP_BLUR) {
stopWatchingForValueChange();
}
}
// For IE8 and IE9.
function getTargetInstForInputEventPolyfill(topLevelType, targetInst) {
if (topLevelType === TOP_SELECTION_CHANGE || topLevelType === TOP_KEY_UP || topLevelType === TOP_KEY_DOWN) {
// 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);
}
}
/**
* SECTION: handle `click` event
*/
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');
}
function getTargetInstForClickEvent(topLevelType, targetInst) {
if (topLevelType === TOP_CLICK) {
return getInstIfValueChanged(targetInst);
}
}
function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) {
if (topLevelType === TOP_INPUT || topLevelType === TOP_CHANGE) {
return getInstIfValueChanged(targetInst);
}
}
function handleControlledInputBlur(node) {
var state = node._wrapperState;
if (!state || !state.controlled || node.type !== 'number') {
return;
}
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
*/
var ChangeEventPlugin = {
eventTypes: eventTypes$1,
_isInputEventSupported: isInputEventSupported,
extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window;
var getTargetInstFunc = void 0,
handleEventFunc = void 0;
if (shouldUseChangeEvent(targetNode)) {
getTargetInstFunc = getTargetInstForChangeEvent;
} else if (isTextInputElement(targetNode)) {
if (isInputEventSupported) {
getTargetInstFunc = getTargetInstForInputOrChangeEvent;
} else {
getTargetInstFunc = getTargetInstForInputEventPolyfill;
handleEventFunc = handleEventsForInputEventPolyfill;
}
} else if (shouldUseClickEvent(targetNode)) {
getTargetInstFunc = getTargetInstForClickEvent;
}
if (getTargetInstFunc) {
var inst = getTargetInstFunc(topLevelType, targetInst);
if (inst) {
var event = createAndAccumulateChangeEvent(inst, nativeEvent, nativeEventTarget);
return event;
}
}
if (handleEventFunc) {
handleEventFunc(topLevelType, targetNode, targetInst);
}
// When blurring, set the value attribute for number inputs
if (topLevelType === TOP_BLUR) {
handleControlledInputBlur(targetNode);
}
}
};
/**
* Module that is injectable into `EventPluginHub`, that specifies a
* deterministic ordering of `EventPlugin`s. A convenient way to reason about
* plugins, without having to package every one of them. This is better than
* having plugins be ordered in the same order that they are injected because
* that ordering would be influenced by the packaging order.
* `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
* preventing default on events is convenient in `SimpleEventPlugin` handlers.
*/
var DOMEventPluginOrder = ['ResponderEventPlugin', 'SimpleEventPlugin', 'EnterLeaveEventPlugin', 'ChangeEventPlugin', 'SelectEventPlugin', 'BeforeInputEventPlugin'];
var SyntheticUIEvent = SyntheticEvent.extend({
view: null,
detail: null
});
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.
/**
* Translation from modifier key to the associated property in the event.
*/
function modifierStateGetter(keyArg) {
var syntheticEvent = this;
var nativeEvent = syntheticEvent.nativeEvent;
if (nativeEvent.getModifierState) {
return nativeEvent.getModifierState(keyArg);
}
var keyProp = modifierKeyToProp[keyArg];
return keyProp ? !!nativeEvent[keyProp] : false;
}
function getEventModifierState(nativeEvent) {
return modifierStateGetter;
}
var previousScreenX = 0;
var previousScreenY = 0;
// Use flags to signal movementX/Y has already been set
var isMovementXSet = false;
var isMovementYSet = false;
/**
* @interface MouseEvent
*/
var SyntheticMouseEvent = SyntheticUIEvent.extend({
screenX: null,
screenY: null,
clientX: null,
clientY: null,
pageX: null,
pageY: null,
ctrlKey: null,
shiftKey: null,
altKey: null,
metaKey: null,
getModifierState: getEventModifierState,
button: null,
buttons: null,
relatedTarget: function (event) {
return event.relatedTarget || (event.fromElement === event.srcElement ? event.toElement : event.fromElement);
},
movementX: function (event) {
if ('movementX' in event) {
return event.movementX;
}
var screenX = previousScreenX;
previousScreenX = event.screenX;
if (!isMovementXSet) {
isMovementXSet = true;
return 0;
}
return event.type === 'mousemove' ? event.screenX - screenX : 0;
},
movementY: function (event) {
if ('movementY' in event) {
return event.movementY;
}
var screenY = previousScreenY;
previousScreenY = event.screenY;
if (!isMovementYSet) {
isMovementYSet = true;
return 0;
}
return event.type === 'mousemove' ? event.screenY - screenY : 0;
}
});
/**
* @interface PointerEvent
*/
var SyntheticPointerEvent = SyntheticMouseEvent.extend({
pointerId: null,
width: null,
height: null,
pressure: null,
tangentialPressure: null,
tiltX: null,
tiltY: null,
twist: null,
pointerType: null,
isPrimary: null
});
var eventTypes$2 = {
mouseEnter: {
registrationName: 'onMouseEnter',
dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER]
},
mouseLeave: {
registrationName: 'onMouseLeave',
dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER]
},
pointerEnter: {
registrationName: 'onPointerEnter',
dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER]
},
pointerLeave: {
registrationName: 'onPointerLeave',
dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER]
}
};
var EnterLeaveEventPlugin = {
eventTypes: eventTypes$2,
/**
* 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.
*/
extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var isOverEvent = topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER;
var isOutEvent = topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
if (isOverEvent && (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
return null;
}
if (!isOutEvent && !isOverEvent) {
// Must not be a mouse or pointer in or out - ignoring.
return null;
}
var win = void 0;
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 {
win = window;
}
}
var from = void 0;
var to = void 0;
if (isOutEvent) {
from = targetInst;
var related = nativeEvent.relatedTarget || nativeEvent.toElement;
to = related ? getClosestInstanceFromNode(related) : null;
} else {
// Moving to a node from outside the window.
from = null;
to = targetInst;
}
if (from === to) {
// Nothing pertains to our managed components.
return null;
}
var eventInterface = void 0,
leaveEventType = void 0,
enterEventType = void 0,
eventTypePrefix = void 0;
if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
eventInterface = SyntheticMouseEvent;
leaveEventType = eventTypes$2.mouseLeave;
enterEventType = eventTypes$2.mouseEnter;
eventTypePrefix = 'mouse';
} else if (topLevelType === TOP_POINTER_OUT || topLevelType === TOP_POINTER_OVER) {
eventInterface = SyntheticPointerEvent;
leaveEventType = eventTypes$2.pointerLeave;
enterEventType = eventTypes$2.pointerEnter;
eventTypePrefix = 'pointer';
}
var fromNode = from == null ? win : getNodeFromInstance$1(from);
var toNode = to == null ? win : getNodeFromInstance$1(to);
var leave = eventInterface.getPooled(leaveEventType, from, nativeEvent, nativeEventTarget);
leave.type = eventTypePrefix + 'leave';
leave.target = fromNode;
leave.relatedTarget = toNode;
var enter = eventInterface.getPooled(enterEventType, to, nativeEvent, nativeEventTarget);
enter.type = eventTypePrefix + 'enter';
enter.target = toNode;
enter.relatedTarget = fromNode;
accumulateEnterLeaveDispatches(leave, enter, from, to);
return [leave, enter];
}
};
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
*/
function is(x, y) {
return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare
;
}
var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
/**
* Performs equality by iterating through keys on an object and returning false
* when any key has values which are not strictly equal between the arguments.
* Returns true when the values of all keys are strictly equal.
*/
function shallowEqual(objA, objB) {
if (is(objA, objB)) {
return true;
}
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
var keysA = Object.keys(objA);
var keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
for (var i = 0; i < keysA.length; i++) {
if (!hasOwnProperty$1.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
return false;
}
}
return true;
}
/**
* `ReactInstanceMap` maintains a mapping from a public facing stateful
* instance (key) and the internal representation (value). This allows public
* methods to accept the user facing instance as an argument and map them back
* to internal methods.
*
* Note that this module is currently shared and assumed to be stateless.
* If this becomes an actual Map, that will break.
*/
/**
* This API should be called `delete` but we'd have to make sure to always
* transform these to strings for IE support. When this transform is fully
* supported we can rename it.
*/
function get(key) {
return key._reactInternalFiber;
}
function has(key) {
return key._reactInternalFiber !== undefined;
}
function set(key, value) {
key._reactInternalFiber = value;
}
// Don't change these two values. They're used by React Dev Tools.
var NoEffect = /* */0;
var PerformedWork = /* */1;
// You can change the rest (and add more).
var Placement = /* */2;
var Update = /* */4;
var PlacementAndUpdate = /* */6;
var Deletion = /* */8;
var ContentReset = /* */16;
var Callback = /* */32;
var DidCapture = /* */64;
var Ref = /* */128;
var Snapshot = /* */256;
var Passive = /* */512;
// Passive & Update & Callback & Ref & Snapshot
var LifecycleEffectMask = /* */932;
// Union of all host effects
var HostEffectMask = /* */1023;
var Incomplete = /* */1024;
var ShouldCapture = /* */2048;
var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner;
var MOUNTING = 1;
var MOUNTED = 2;
var UNMOUNTED = 3;
function isFiberMountedImpl(fiber) {
var node = fiber;
if (!fiber.alternate) {
// If there is no alternate, this might be a new tree that isn't inserted
// yet. If it is, then it will have a pending insertion effect on it.
if ((node.effectTag & Placement) !== NoEffect) {
return MOUNTING;
}
while (node.return) {
node = node.return;
if ((node.effectTag & Placement) !== NoEffect) {
return MOUNTING;
}
}
} else {
while (node.return) {
node = node.return;
}
}
if (node.tag === HostRoot) {
// TODO: Check if this was a nested HostRoot when used with
// renderContainerIntoSubtree.
return MOUNTED;
}
// If we didn't hit the root, that means that we're in an disconnected tree
// that has been unmounted.
return UNMOUNTED;
}
function isFiberMounted(fiber) {
return isFiberMountedImpl(fiber) === MOUNTED;
}
function isMounted(component) {
var fiber = get(component);
if (!fiber) {
return false;
}
return isFiberMountedImpl(fiber) === MOUNTED;
}
function assertIsMounted(fiber) {
!(isFiberMountedImpl(fiber) === MOUNTED) ? reactProdInvariant('188') : void 0;
}
function findCurrentFiberUsingSlowPath(fiber) {
var alternate = fiber.alternate;
if (!alternate) {
// If there is no alternate, then we only need to check if it is mounted.
var state = isFiberMountedImpl(fiber);
!(state !== UNMOUNTED) ? reactProdInvariant('188') : void 0;
if (state === MOUNTING) {
return null;
}
return fiber;
}
// If we have two possible branches, we'll walk backwards up to the root
// to see what path the root points to. On the way we may hit one of the
// special cases and we'll deal with them.
var a = fiber;
var b = alternate;
while (true) {
var parentA = a.return;
var parentB = parentA ? parentA.alternate : null;
if (!parentA || !parentB) {
// We're at the root.
break;
}
// If both copies of the parent fiber point to the same child, we can
// assume that the child is current. This happens when we bailout on low
// priority: the bailed out fiber's child reuses the current child.
if (parentA.child === parentB.child) {
var child = parentA.child;
while (child) {
if (child === a) {
// We've determined that A is the current branch.
assertIsMounted(parentA);
return fiber;
}
if (child === b) {
// We've determined that B is the current branch.
assertIsMounted(parentA);
return alternate;
}
child = child.sibling;
}
// We should never have an alternate for any mounting node. So the only
// way this could possibly happen is if this was unmounted, if at all.
reactProdInvariant('188');
}
if (a.return !== b.return) {
// The return pointer of A and the return pointer of B point to different
// fibers. We assume that return pointers never criss-cross, so A must
// belong to the child set of A.return, and B must belong to the child
// set of B.return.
a = parentA;
b = parentB;
} else {
// The return pointers point to the same fiber. We'll have to use the
// default, slow path: scan the child sets of each parent alternate to see
// which child belongs to which set.
//
// Search parent A's child set
var didFindChild = false;
var _child = parentA.child;
while (_child) {
if (_child === a) {
didFindChild = true;
a = parentA;
b = parentB;
break;
}
if (_child === b) {
didFindChild = true;
b = parentA;
a = parentB;
break;
}
_child = _child.sibling;
}
if (!didFindChild) {
// Search parent B's child set
_child = parentB.child;
while (_child) {
if (_child === a) {
didFindChild = true;
a = parentB;
b = parentA;
break;
}
if (_child === b) {
didFindChild = true;
b = parentB;
a = parentA;
break;
}
_child = _child.sibling;
}
!didFindChild ? reactProdInvariant('189') : void 0;
}
}
!(a.alternate === b) ? reactProdInvariant('190') : void 0;
}
// If the root is not a host container, we're in a disconnected tree. I.e.
// unmounted.
!(a.tag === HostRoot) ? reactProdInvariant('188') : void 0;
if (a.stateNode.current === a) {
// We've determined that A is the current branch.
return fiber;
}
// Otherwise B has to be current branch.
return alternate;
}
function findCurrentHostFiber(parent) {
var currentParent = findCurrentFiberUsingSlowPath(parent);
if (!currentParent) {
return null;
}
// Next we'll drill down this component to find the first HostComponent/Text.
var node = currentParent;
while (true) {
if (node.tag === HostComponent || node.tag === HostText) {
return node;
} else if (node.child) {
node.child.return = node;
node = node.child;
continue;
}
if (node === currentParent) {
return null;
}
while (!node.sibling) {
if (!node.return || node.return === currentParent) {
return null;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
// Flow needs the return null here, but ESLint complains about it.
// eslint-disable-next-line no-unreachable
return null;
}
function addEventBubbleListener(element, eventType, listener) {
element.addEventListener(eventType, listener, false);
}
function addEventCaptureListener(element, eventType, listener) {
element.addEventListener(eventType, listener, true);
}
/**
* @interface Event
*/
var SyntheticAnimationEvent = SyntheticEvent.extend({
animationName: null,
elapsedTime: null,
pseudoElement: null
});
/**
* @interface Event
*/
var SyntheticClipboardEvent = SyntheticEvent.extend({
clipboardData: function (event) {
return 'clipboardData' in event ? event.clipboardData : window.clipboardData;
}
});
/**
* @interface FocusEvent
*/
var SyntheticFocusEvent = SyntheticUIEvent.extend({
relatedTarget: null
});
/**
* `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 = void 0;
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.
if (charCode === 10) {
charCode = 13;
}
// Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
// Must not discard the (non-)printable Enter-key.
if (charCode >= 32 || charCode === 13) {
return charCode;
}
return 0;
}
/**
* Normalization of deprecated HTML5 `key` values
*/
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
*/
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;
if (key !== 'Unidentified') {
return key;
}
}
// Browser does not implement `key`, polyfill as much of it as we can.
if (nativeEvent.type === 'keypress') {
var charCode = getEventCharCode(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.
return translateToKey[nativeEvent.keyCode] || 'Unidentified';
}
return '';
}
/**
* @interface KeyboardEvent
*/
var SyntheticKeyboardEvent = SyntheticUIEvent.extend({
key: getEventKey,
location: null,
ctrlKey: null,
shiftKey: null,
altKey: null,
metaKey: null,
repeat: null,
locale: null,
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(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;
}
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(event);
}
if (event.type === 'keydown' || event.type === 'keyup') {
return event.keyCode;
}
return 0;
}
});
/**
* @interface DragEvent
*/
var SyntheticDragEvent = SyntheticMouseEvent.extend({
dataTransfer: null
});
/**
* @interface TouchEvent
*/
var SyntheticTouchEvent = SyntheticUIEvent.extend({
touches: null,
targetTouches: null,
changedTouches: null,
altKey: null,
metaKey: null,
ctrlKey: null,
shiftKey: null,
getModifierState: getEventModifierState
});
/**
* @interface Event
*/
var SyntheticTransitionEvent = SyntheticEvent.extend({
propertyName: null,
elapsedTime: null,
pseudoElement: null
});
/**
* @interface WheelEvent
*/
var SyntheticWheelEvent = SyntheticMouseEvent.extend({
deltaX: function (event) {
return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
'wheelDeltaX' in event ? -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 ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
'wheelDelta' in event ? -event.wheelDelta : 0;
},
deltaZ: null,
// 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: null
});
/**
* Turns
* ['abort', ...]
* into
* eventTypes = {
* 'abort': {
* phasedRegistrationNames: {
* bubbled: 'onAbort',
* captured: 'onAbortCapture',
* },
* dependencies: [TOP_ABORT],
* },
* ...
* };
* topLevelEventsToDispatchConfig = new Map([
* [TOP_ABORT, { sameConfig }],
* ]);
*/
var interactiveEventTypeNames = [[TOP_BLUR, 'blur'], [TOP_CANCEL, 'cancel'], [TOP_CLICK, 'click'], [TOP_CLOSE, 'close'], [TOP_CONTEXT_MENU, 'contextMenu'], [TOP_COPY, 'copy'], [TOP_CUT, 'cut'], [TOP_AUX_CLICK, 'auxClick'], [TOP_DOUBLE_CLICK, 'doubleClick'], [TOP_DRAG_END, 'dragEnd'], [TOP_DRAG_START, 'dragStart'], [TOP_DROP, 'drop'], [TOP_FOCUS, 'focus'], [TOP_INPUT, 'input'], [TOP_INVALID, 'invalid'], [TOP_KEY_DOWN, 'keyDown'], [TOP_KEY_PRESS, 'keyPress'], [TOP_KEY_UP, 'keyUp'], [TOP_MOUSE_DOWN, 'mouseDown'], [TOP_MOUSE_UP, 'mouseUp'], [TOP_PASTE, 'paste'], [TOP_PAUSE, 'pause'], [TOP_PLAY, 'play'], [TOP_POINTER_CANCEL, 'pointerCancel'], [TOP_POINTER_DOWN, 'pointerDown'], [TOP_POINTER_UP, 'pointerUp'], [TOP_RATE_CHANGE, 'rateChange'], [TOP_RESET, 'reset'], [TOP_SEEKED, 'seeked'], [TOP_SUBMIT, 'submit'], [TOP_TOUCH_CANCEL, 'touchCancel'], [TOP_TOUCH_END, 'touchEnd'], [TOP_TOUCH_START, 'touchStart'], [TOP_VOLUME_CHANGE, 'volumeChange']];
var nonInteractiveEventTypeNames = [[TOP_ABORT, 'abort'], [TOP_ANIMATION_END, 'animationEnd'], [TOP_ANIMATION_ITERATION, 'animationIteration'], [TOP_ANIMATION_START, 'animationStart'], [TOP_CAN_PLAY, 'canPlay'], [TOP_CAN_PLAY_THROUGH, 'canPlayThrough'], [TOP_DRAG, 'drag'], [TOP_DRAG_ENTER, 'dragEnter'], [TOP_DRAG_EXIT, 'dragExit'], [TOP_DRAG_LEAVE, 'dragLeave'], [TOP_DRAG_OVER, 'dragOver'], [TOP_DURATION_CHANGE, 'durationChange'], [TOP_EMPTIED, 'emptied'], [TOP_ENCRYPTED, 'encrypted'], [TOP_ENDED, 'ended'], [TOP_ERROR, 'error'], [TOP_GOT_POINTER_CAPTURE, 'gotPointerCapture'], [TOP_LOAD, 'load'], [TOP_LOADED_DATA, 'loadedData'], [TOP_LOADED_METADATA, 'loadedMetadata'], [TOP_LOAD_START, 'loadStart'], [TOP_LOST_POINTER_CAPTURE, 'lostPointerCapture'], [TOP_MOUSE_MOVE, 'mouseMove'], [TOP_MOUSE_OUT, 'mouseOut'], [TOP_MOUSE_OVER, 'mouseOver'], [TOP_PLAYING, 'playing'], [TOP_POINTER_MOVE, 'pointerMove'], [TOP_POINTER_OUT, 'pointerOut'], [TOP_POINTER_OVER, 'pointerOver'], [TOP_PROGRESS, 'progress'], [TOP_SCROLL, 'scroll'], [TOP_SEEKING, 'seeking'], [TOP_STALLED, 'stalled'], [TOP_SUSPEND, 'suspend'], [TOP_TIME_UPDATE, 'timeUpdate'], [TOP_TOGGLE, 'toggle'], [TOP_TOUCH_MOVE, 'touchMove'], [TOP_TRANSITION_END, 'transitionEnd'], [TOP_WAITING, 'waiting'], [TOP_WHEEL, 'wheel']];
var eventTypes$4 = {};
var topLevelEventsToDispatchConfig = {};
function addEventTypeNameToConfig(_ref, isInteractive) {
var topEvent = _ref[0],
event = _ref[1];
var capitalizedEvent = event[0].toUpperCase() + event.slice(1);
var onEvent = 'on' + capitalizedEvent;
var type = {
phasedRegistrationNames: {
bubbled: onEvent,
captured: onEvent + 'Capture'
},
dependencies: [topEvent],
isInteractive: isInteractive
};
eventTypes$4[event] = type;
topLevelEventsToDispatchConfig[topEvent] = type;
}
interactiveEventTypeNames.forEach(function (eventTuple) {
addEventTypeNameToConfig(eventTuple, true);
});
nonInteractiveEventTypeNames.forEach(function (eventTuple) {
addEventTypeNameToConfig(eventTuple, false);
});
var SimpleEventPlugin = {
eventTypes: eventTypes$4,
isInteractiveTopLevelEventType: function (topLevelType) {
var config = topLevelEventsToDispatchConfig[topLevelType];
return config !== undefined && config.isInteractive === true;
},
extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
if (!dispatchConfig) {
return null;
}
var EventConstructor = void 0;
switch (topLevelType) {
case TOP_KEY_PRESS:
// 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 null;
}
/* falls through */
case TOP_KEY_DOWN:
case TOP_KEY_UP:
EventConstructor = SyntheticKeyboardEvent;
break;
case TOP_BLUR:
case TOP_FOCUS:
EventConstructor = SyntheticFocusEvent;
break;
case TOP_CLICK:
// Firefox creates a click event on right mouse clicks. This removes the
// unwanted click events.
if (nativeEvent.button === 2) {
return null;
}
/* falls through */
case TOP_AUX_CLICK:
case TOP_DOUBLE_CLICK:
case TOP_MOUSE_DOWN:
case TOP_MOUSE_MOVE:
case TOP_MOUSE_UP:
// TODO: Disabled elements should not respond to mouse events
/* falls through */
case TOP_MOUSE_OUT:
case TOP_MOUSE_OVER:
case TOP_CONTEXT_MENU:
EventConstructor = SyntheticMouseEvent;
break;
case TOP_DRAG:
case TOP_DRAG_END:
case TOP_DRAG_ENTER:
case TOP_DRAG_EXIT:
case TOP_DRAG_LEAVE:
case TOP_DRAG_OVER:
case TOP_DRAG_START:
case TOP_DROP:
EventConstructor = SyntheticDragEvent;
break;
case TOP_TOUCH_CANCEL:
case TOP_TOUCH_END:
case TOP_TOUCH_MOVE:
case TOP_TOUCH_START:
EventConstructor = SyntheticTouchEvent;
break;
case TOP_ANIMATION_END:
case TOP_ANIMATION_ITERATION:
case TOP_ANIMATION_START:
EventConstructor = SyntheticAnimationEvent;
break;
case TOP_TRANSITION_END:
EventConstructor = SyntheticTransitionEvent;
break;
case TOP_SCROLL:
EventConstructor = SyntheticUIEvent;
break;
case TOP_WHEEL:
EventConstructor = SyntheticWheelEvent;
break;
case TOP_COPY:
case TOP_CUT:
case TOP_PASTE:
EventConstructor = SyntheticClipboardEvent;
break;
case TOP_GOT_POINTER_CAPTURE:
case TOP_LOST_POINTER_CAPTURE:
case TOP_POINTER_CANCEL:
case TOP_POINTER_DOWN:
case TOP_POINTER_MOVE:
case TOP_POINTER_OUT:
case TOP_POINTER_OVER:
case TOP_POINTER_UP:
EventConstructor = SyntheticPointerEvent;
break;
default:
// HTML Events
EventConstructor = SyntheticEvent;
break;
}
var event = EventConstructor.getPooled(dispatchConfig, targetInst, nativeEvent, nativeEventTarget);
accumulateTwoPhaseDispatches(event);
return event;
}
};
var isInteractiveTopLevelEventType = SimpleEventPlugin.isInteractiveTopLevelEventType;
var CALLBACK_BOOKKEEPING_POOL_SIZE = 10;
var callbackBookkeepingPool = [];
/**
* Find the deepest React component completely containing the root of the
* passed-in instance (for use when entire React trees are nested within each
* other). If React trees are not nested, returns null.
*/
function findRootContainerNode(inst) {
// TODO: It may be a good idea to cache this to prevent unnecessary DOM
// traversal, but caching is difficult to do correctly without using a
// mutation observer to listen for all DOM changes.
while (inst.return) {
inst = inst.return;
}
if (inst.tag !== HostRoot) {
// This can happen if we're in a detached tree.
return null;
}
return inst.stateNode.containerInfo;
}
// Used to store ancestor hierarchy in top level callback
function getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst) {
if (callbackBookkeepingPool.length) {
var instance = callbackBookkeepingPool.pop();
instance.topLevelType = topLevelType;
instance.nativeEvent = nativeEvent;
instance.targetInst = targetInst;
return instance;
}
return {
topLevelType: topLevelType,
nativeEvent: nativeEvent,
targetInst: targetInst,
ancestors: []
};
}
function releaseTopLevelCallbackBookKeeping(instance) {
instance.topLevelType = null;
instance.nativeEvent = null;
instance.targetInst = null;
instance.ancestors.length = 0;
if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) {
callbackBookkeepingPool.push(instance);
}
}
function handleTopLevel(bookKeeping) {
var targetInst = bookKeeping.targetInst;
// Loop through the hierarchy, in case there's any nested components.
// It's important that we build the array of ancestors before calling any
// event handlers, because event handlers can modify the DOM, leading to
// inconsistencies with ReactMount's node cache. See #1105.
var ancestor = targetInst;
do {
if (!ancestor) {
bookKeeping.ancestors.push(ancestor);
break;
}
var root = findRootContainerNode(ancestor);
if (!root) {
break;
}
bookKeeping.ancestors.push(ancestor);
ancestor = getClosestInstanceFromNode(root);
} while (ancestor);
for (var i = 0; i < bookKeeping.ancestors.length; i++) {
targetInst = bookKeeping.ancestors[i];
runExtractedEventsInBatch(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent));
}
}
// TODO: can we stop exporting these?
var _enabled = true;
function setEnabled(enabled) {
_enabled = !!enabled;
}
function isEnabled() {
return _enabled;
}
/**
* Traps top-level events by using event bubbling.
*
* @param {number} topLevelType Number from `TopLevelEventTypes`.
* @param {object} element Element on which to attach listener.
* @return {?object} An object with a remove function which will forcefully
* remove the listener.
* @internal
*/
function trapBubbledEvent(topLevelType, element) {
if (!element) {
return null;
}
var dispatch = isInteractiveTopLevelEventType(topLevelType) ? dispatchInteractiveEvent : dispatchEvent;
addEventBubbleListener(element, getRawEventName(topLevelType),
// Check if interactive and wrap in interactiveUpdates
dispatch.bind(null, topLevelType));
}
/**
* Traps a top-level event by using event capturing.
*
* @param {number} topLevelType Number from `TopLevelEventTypes`.
* @param {object} element Element on which to attach listener.
* @return {?object} An object with a remove function which will forcefully
* remove the listener.
* @internal
*/
function trapCapturedEvent(topLevelType, element) {
if (!element) {
return null;
}
var dispatch = isInteractiveTopLevelEventType(topLevelType) ? dispatchInteractiveEvent : dispatchEvent;
addEventCaptureListener(element, getRawEventName(topLevelType),
// Check if interactive and wrap in interactiveUpdates
dispatch.bind(null, topLevelType));
}
function dispatchInteractiveEvent(topLevelType, nativeEvent) {
interactiveUpdates(dispatchEvent, topLevelType, nativeEvent);
}
function dispatchEvent(topLevelType, nativeEvent) {
if (!_enabled) {
return;
}
var nativeEventTarget = getEventTarget(nativeEvent);
var targetInst = getClosestInstanceFromNode(nativeEventTarget);
if (targetInst !== null && typeof targetInst.tag === 'number' && !isFiberMounted(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;
}
var bookKeeping = getTopLevelCallbackBookKeeping(topLevelType, nativeEvent, targetInst);
try {
// Event queue being processed in the same cycle allows
// `preventDefault`.
batchedUpdates(handleTopLevel, bookKeeping);
} finally {
releaseTopLevelCallbackBookKeeping(bookKeeping);
}
}
/**
* Summary of `ReactBrowserEventEmitter` event handling:
*
* - Top-level delegation is used to trap most native browser events. This
* may only occur in the main thread and is the responsibility of
* ReactDOMEventListener, which is injected and can therefore support
* pluggable event sources. This is the only work that occurs in the main
* thread.
*
* - We normalize and de-duplicate events to account for browser quirks. This
* may be done in the worker thread.
*
* - Forward these native events (with the associated top-level type used to
* trap it) to `EventPluginHub`, which in turn will ask plugins if they want
* to extract any synthetic events.
*
* - The `EventPluginHub` will then process each event by annotating them with
* "dispatches", a sequence of listeners and IDs that care about that event.
*
* - The `EventPluginHub` then dispatches the events.
*
* Overview of React and the event system:
*
* +------------+ .
* | DOM | .
* +------------+ .
* | .
* v .
* +------------+ .
* | ReactEvent | .
* | Listener | .
* +------------+ . +-----------+
* | . +--------+|SimpleEvent|
* | . | |Plugin |
* +-----|------+ . v +-----------+
* | | | . +--------------+ +------------+
* | +-----------.--->|EventPluginHub| | Event |
* | | . | | +-----------+ | Propagators|
* | ReactEvent | . | | |TapEvent | |------------|
* | Emitter | . | |<---+|Plugin | |other plugin|
* | | . | | +-----------+ | utilities |
* | +-----------.--->| | +------------+
* | | | . +--------------+
* +-----|------+ . ^ +-----------+
* | . | |Enter/Leave|
* + . +-------+|Plugin |
* +-------------+ . +-----------+
* | application | .
* |-------------| .
* | | .
* | | .
* +-------------+ .
* .
* React Core . General Purpose Event Plugin System
*/
var alreadyListeningTo = {};
var reactTopListenersCounter = 0;
/**
* To ensure no conflicts with other potential React instances on the page
*/
var topListenersIDKey = '_reactListenersID' + ('' + Math.random()).slice(2);
function getListeningForDocument(mountAt) {
// In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
// directly.
if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
mountAt[topListenersIDKey] = reactTopListenersCounter++;
alreadyListeningTo[mountAt[topListenersIDKey]] = {};
}
return alreadyListeningTo[mountAt[topListenersIDKey]];
}
/**
* We listen for bubbled touch events on the document object.
*
* Firefox v8.01 (and possibly others) exhibited strange behavior when
* mounting `onmousemove` events at some node that was not the document
* element. The symptoms were that if your mouse is not moving over something
* contained within that mount point (for example on the background) the
* top-level listeners for `onmousemove` won't be called. However, if you
* register the `mousemove` on the document object, then it will of course
* catch all `mousemove`s. This along with iOS quirks, justifies restricting
* top-level listeners to the document object only, at least for these
* movement types of events and possibly all events.
*
*
* Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
* they bubble to document.
*
* @param {string} registrationName Name of listener (e.g. `onClick`).
* @param {object} mountAt Container where to mount the listener
*/
function listenTo(registrationName, mountAt) {
var isListening = getListeningForDocument(mountAt);
var dependencies = registrationNameDependencies[registrationName];
for (var i = 0; i < dependencies.length; i++) {
var dependency = dependencies[i];
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
switch (dependency) {
case TOP_SCROLL:
trapCapturedEvent(TOP_SCROLL, mountAt);
break;
case TOP_FOCUS:
case TOP_BLUR:
trapCapturedEvent(TOP_FOCUS, mountAt);
trapCapturedEvent(TOP_BLUR, mountAt);
// We set the flag for a single dependency later in this function,
// but this ensures we mark both as attached rather than just one.
isListening[TOP_BLUR] = true;
isListening[TOP_FOCUS] = true;
break;
case TOP_CANCEL:
case TOP_CLOSE:
if (isEventSupported(getRawEventName(dependency))) {
trapCapturedEvent(dependency, mountAt);
}
break;
case TOP_INVALID:
case TOP_SUBMIT:
case TOP_RESET:
// We listen to them on the target DOM elements.
// Some of them bubble so we don't want them to fire twice.
break;
default:
// By default, listen on the top level to all non-media events.
// Media events don't bubble so adding the listener wouldn't do anything.
var isMediaEvent = mediaEventTypes.indexOf(dependency) !== -1;
if (!isMediaEvent) {
trapBubbledEvent(dependency, mountAt);
}
break;
}
isListening[dependency] = true;
}
}
}
function isListeningToAllDependencies(registrationName, mountAt) {
var isListening = getListeningForDocument(mountAt);
var dependencies = registrationNameDependencies[registrationName];
for (var i = 0; i < dependencies.length; i++) {
var dependency = dependencies[i];
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
return false;
}
}
return true;
}
function getActiveElement(doc) {
doc = doc || (typeof document !== 'undefined' ? document : undefined);
if (typeof doc === 'undefined') {
return null;
}
try {
return doc.activeElement || doc.body;
} catch (e) {
return doc.body;
}
}
/**
* Given any node return the first leaf node without children.
*
* @param {DOMElement|DOMTextNode} node
* @return {DOMElement|DOMTextNode}
*/
function getLeafNode(node) {
while (node && node.firstChild) {
node = node.firstChild;
}
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;
}
}
/**
* 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;
if (nodeStart <= offset && nodeEnd >= offset) {
return {
node: node,
offset: offset - nodeStart
};
}
nodeStart = nodeEnd;
}
node = getLeafNode(getSiblingNode(node));
}
}
/**
* @param {DOMElement} outerNode
* @return {?object}
*/
function getOffsets(outerNode) {
var ownerDocument = outerNode.ownerDocument;
var win = ownerDocument && ownerDocument.defaultView || window;
var selection = win.getSelection && win.getSelection();
if (!selection || selection.rangeCount === 0) {
return null;
}
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 <input type="number">. 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
try {
/* eslint-disable no-unused-expressions */
anchorNode.nodeType;
focusNode.nodeType;
/* eslint-enable no-unused-expressions */
} catch (e) {
return null;
}
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.
*/
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;
outer: while (true) {
var next = null;
while (true) {
if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) {
start = length + anchorOffset;
}
if (node === focusNode && (focusOffset === 0 || node.nodeType === TEXT_NODE)) {
end = length + focusOffset;
}
if (node.nodeType === TEXT_NODE) {
length += node.nodeValue.length;
}
if ((next = node.firstChild) === null) {
break;
}
// Moving from `node` to its first child `next`.
parentNode = node;
node = next;
}
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;
}
return {
start: start,
end: end
};
}
/**
* 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)
if (!win.getSelection) {
return;
}
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 startMarker = getNodeForCharacterOffset(node, start);
var endMarker = getNodeForCharacterOffset(node, end);
if (startMarker && endMarker) {
if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) {
return;
}
var range = doc.createRange();
range.setStart(startMarker.node, startMarker.offset);
selection.removeAllRanges();
if (start > end) {
selection.addRange(range);
selection.extend(endMarker.node, endMarker.offset);
} else {
range.setEnd(endMarker.node, endMarker.offset);
selection.addRange(range);
}
}
}
function isTextNode(node) {
return node && node.nodeType === TEXT_NODE;
}
function containsNode(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(outerNode, innerNode.parentNode);
} else if ('contains' in outerNode) {
return outerNode.contains(innerNode);
} else if (outerNode.compareDocumentPosition) {
return !!(outerNode.compareDocumentPosition(innerNode) & 16);
} else {
return false;
}
}
function isInDocument(node) {
return node && node.ownerDocument && containsNode(node.ownerDocument.documentElement, node);
}
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.
return typeof iframe.contentWindow.location.href === 'string';
} catch (err) {
return false;
}
}
function getActiveElementDeep() {
var win = window;
var element = getActiveElement();
while (element instanceof win.HTMLIFrameElement) {
if (isSameOriginFrame(element)) {
win = element.contentWindow;
} else {
return element;
}
element = getActiveElement(win.document);
}
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.
*/
/**
* @hasSelectionCapabilities: we get the element types that support selection
* from https://html.spec.whatwg.org/#do-not-apply, looking at `selectionStart`
* and `selectionEnd` rows.
*/
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.
*/
function restoreSelection(priorSelectionInformation) {
var curFocusedElem = getActiveElementDeep();
var priorFocusedElem = priorSelectionInformation.focusedElem;
var priorSelectionRange = priorSelectionInformation.selectionRange;
if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) {
if (priorSelectionRange !== null && hasSelectionCapabilities(priorFocusedElem)) {
setSelection(priorFocusedElem, priorSelectionRange);
}
// Focusing a node can change the scroll position, which is undesirable
var ancestors = [];
var ancestor = priorFocusedElem;
while (ancestor = ancestor.parentNode) {
if (ancestor.nodeType === ELEMENT_NODE) {
ancestors.push({
element: ancestor,
left: ancestor.scrollLeft,
top: ancestor.scrollTop
});
}
}
if (typeof priorFocusedElem.focus === 'function') {
priorFocusedElem.focus();
}
for (var i = 0; i < ancestors.length; i++) {
var info = ancestors[i];
info.element.scrollLeft = info.left;
info.element.scrollTop = info.top;
}
}
}
/**
* @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 = void 0;
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);
}
return selection || { start: 0, end: 0 };
}
/**
* @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,
end = offsets.end;
if (end === undefined) {
end = start;
}
if ('selectionStart' in input) {
input.selectionStart = start;
input.selectionEnd = Math.min(end, input.value.length);
} else {
setOffsets(input, offsets);
}
}
var skipSelectionChangeEvent = canUseDOM && 'documentMode' in document && document.documentMode <= 11;
var eventTypes$3 = {
select: {
phasedRegistrationNames: {
bubbled: 'onSelect',
captured: 'onSelectCapture'
},
dependencies: [TOP_BLUR, TOP_CONTEXT_MENU, TOP_DRAG_END, TOP_FOCUS, TOP_KEY_DOWN, TOP_KEY_UP, TOP_MOUSE_DOWN, TOP_MOUSE_UP, TOP_SELECTION_CHANGE]
}
};
var activeElement$1 = null;
var activeElementInst$1 = 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.
*
* @param {DOMElement} node
* @return {object}
*/
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
};
}
}
/**
* Get document associated with the event target.
*
* @param {object} nativeEventTarget
* @return {Document}
*/
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}
*/
function constructSelectEvent(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$1 == null || activeElement$1 !== getActiveElement(doc)) {
return null;
}
// Only fire when selection has actually changed.
var currentSelection = getSelection(activeElement$1);
if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
lastSelection = currentSelection;
var syntheticEvent = SyntheticEvent.getPooled(eventTypes$3.select, activeElementInst$1, nativeEvent, nativeEventTarget);
syntheticEvent.type = 'select';
syntheticEvent.target = activeElement$1;
accumulateTwoPhaseDispatches(syntheticEvent);
return syntheticEvent;
}
return null;
}
/**
* 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 SelectEventPlugin = {
eventTypes: eventTypes$3,
extractEvents: function (topLevelType, targetInst, nativeEvent, nativeEventTarget) {
var doc = getEventTargetDocument(nativeEventTarget);
// Track whether all listeners exists for this plugin. If none exist, we do
// not extract events. See #3639.
if (!doc || !isListeningToAllDependencies('onSelect', doc)) {
return null;
}
var targetNode = targetInst ? getNodeFromInstance$1(targetInst) : window;
switch (topLevelType) {
// Track the input node that has focus.
case TOP_FOCUS:
if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') {
activeElement$1 = targetNode;
activeElementInst$1 = targetInst;
lastSelection = null;
}
break;
case TOP_BLUR:
activeElement$1 = null;
activeElementInst$1 = null;
lastSelection = null;
break;
// Don't fire the event while the user is dragging. This matches the
// semantics of the native select event.
case TOP_MOUSE_DOWN:
mouseDown = true;
break;
case TOP_CONTEXT_MENU:
case TOP_MOUSE_UP:
case TOP_DRAG_END:
mouseDown = false;
return constructSelectEvent(nativeEvent, nativeEventTarget);
// 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 TOP_SELECTION_CHANGE:
if (skipSelectionChangeEvent) {
break;
}
// falls through
case TOP_KEY_DOWN:
case TOP_KEY_UP:
return constructSelectEvent(nativeEvent, nativeEventTarget);
}
return null;
}
};
/**
* Inject modules for resolving DOM hierarchy and plugin ordering.
*/
injection.injectEventPluginOrder(DOMEventPluginOrder);
setComponentTree(getFiberCurrentPropsFromNode$1, getInstanceFromNode$1, getNodeFromInstance$1);
/**
* Some important event plugins included by default (without having to require
* them).
*/
injection.injectEventPluginsByName({
SimpleEventPlugin: SimpleEventPlugin,
EnterLeaveEventPlugin: EnterLeaveEventPlugin,
ChangeEventPlugin: ChangeEventPlugin,
SelectEventPlugin: SelectEventPlugin,
BeforeInputEventPlugin: BeforeInputEventPlugin
});
function flattenChildren(children) {
var content = '';
// Flatten children. We'll warn if they are invalid
// during validateProps() which runs for hydration too.
// Note that this would throw on non-element objects.
// Elements are stringified (which is normally irrelevant
// but matters for <fbt>).
React.Children.forEach(children, function (child) {
if (child == null) {
return;
}
content += child;
// Note: we don't warn about invalid children here.
// Instead, this is done separately below so that
// it happens during the hydration codepath too.
});
return content;
}
/**
* Implements an <option> host component that warns when `selected` is set.
*/
function postMountWrapper$1(element, props) {
// value="" should make a value attribute (#6219)
if (props.value != null) {
element.setAttribute('value', toString(getToStringValue(props.value)));
}
}
function getHostProps$1(element, props) {
var hostProps = _assign({ children: undefined }, props);
var content = flattenChildren(props.children);
if (content) {
hostProps.children = content;
}
return hostProps;
}
// TODO: direct imports like some-package/src/* are bad. Fix me.
function updateOptions(node, multiple, propValue, setDefaultSelected) {
var options = node.options;
if (multiple) {
var selectedValues = propValue;
var selectedValue = {};
for (var i = 0; i < selectedValues.length; i++) {
// Prefix to avoid chaos with special keys.
selectedValue['$' + selectedValues[i]] = true;
}
for (var _i = 0; _i < options.length; _i++) {
var selected = selectedValue.hasOwnProperty('$' + options[_i].value);
if (options[_i].selected !== selected) {
options[_i].selected = selected;
}
if (selected && setDefaultSelected) {
options[_i].defaultSelected = true;
}
}
} else {
// Do not set `select.value` as exact behavior isn't consistent across all
// browsers for all cases.
var _selectedValue = toString(getToStringValue(propValue));
var defaultSelected = null;
for (var _i2 = 0; _i2 < options.length; _i2++) {
if (options[_i2].value === _selectedValue) {
options[_i2].selected = true;
if (setDefaultSelected) {
options[_i2].defaultSelected = true;
}
return;
}
if (defaultSelected === null && !options[_i2].disabled) {
defaultSelected = options[_i2];
}
}
if (defaultSelected !== null) {
defaultSelected.selected = true;
}
}
}
/**
* Implements a <select> host component that allows optionally setting the
* props `value` and `defaultValue`. If `multiple` is false, the prop must be a
* stringable. If `multiple` is true, the prop must be an array of stringables.
*
* If `value` is not supplied (or null/undefined), user actions that change the
* selected option will trigger updates to the rendered options.
*
* If it is supplied (and not null/undefined), the rendered options will not
* update in response to user actions. Instead, the `value` prop must change in
* order for the rendered options to update.
*
* If `defaultValue` is provided, any options with the supplied values will be
* selected.
*/
function getHostProps$2(element, props) {
return _assign({}, props, {
value: undefined
});
}
function initWrapperState$1(element, props) {
var node = element;
node._wrapperState = {
wasMultiple: !!props.multiple
};
}
function postMountWrapper$2(element, props) {
var node = element;
node.multiple = !!props.multiple;
var value = props.value;
if (value != null) {
updateOptions(node, !!props.multiple, value, false);
} else if (props.defaultValue != null) {
updateOptions(node, !!props.multiple, props.defaultValue, true);
}
}
function postUpdateWrapper(element, props) {
var node = element;
var wasMultiple = node._wrapperState.wasMultiple;
node._wrapperState.wasMultiple = !!props.multiple;
var value = props.value;
if (value != null) {
updateOptions(node, !!props.multiple, value, false);
} else if (wasMultiple !== !!props.multiple) {
// For simplicity, reapply `defaultValue` if `multiple` is toggled.
if (props.defaultValue != null) {
updateOptions(node, !!props.multiple, props.defaultValue, true);
} else {
// Revert the select back to its default unselected state.
updateOptions(node, !!props.multiple, props.multiple ? [] : '', false);
}
}
}
function restoreControlledState$2(element, props) {
var node = element;
var value = props.value;
if (value != null) {
updateOptions(node, !!props.multiple, value, false);
}
}
/**
* Implements a <textarea> host component that allows setting `value`, and
* `defaultValue`. This differs from the traditional DOM API because value is
* usually set as PCDATA children.
*
* If `value` is not supplied (or null/undefined), user actions that affect the
* value will trigger updates to the element.
*
* If `value` is supplied (and not null/undefined), the rendered element will
* not trigger updates to the element. Instead, the `value` prop must change in
* order for the rendered element to be updated.
*
* The rendered element will be initialized with an empty value, the prop
* `defaultValue` if specified, or the children content (deprecated).
*/
function getHostProps$3(element, props) {
var node = element;
!(props.dangerouslySetInnerHTML == null) ? reactProdInvariant('91') : void 0;
// Always set children to the same thing. In IE9, the selection range will
// get reset if `textContent` is mutated. We could add a check in setTextContent
// to only set the value if/when the value differs from the node value (which would
// completely solve this IE9 bug), but Sebastian+Sophie seemed to like this
// solution. The value can be a boolean or object so that's why it's forced
// to be a string.
var hostProps = _assign({}, props, {
value: undefined,
defaultValue: undefined,
children: toString(node._wrapperState.initialValue)
});
return hostProps;
}
function initWrapperState$2(element, props) {
var node = element;
var initialValue = props.value;
// Only bother fetching default value if we're going to use it
if (initialValue == null) {
var defaultValue = props.defaultValue;
// TODO (yungsters): Remove support for children content in <textarea>.
var children = props.children;
if (children != null) {
!(defaultValue == null) ? reactProdInvariant('92') : void 0;
if (Array.isArray(children)) {
!(children.length <= 1) ? reactProdInvariant('93') : void 0;
children = children[0];
}
defaultValue = children;
}
if (defaultValue == null) {
defaultValue = '';
}
initialValue = defaultValue;
}
node._wrapperState = {
initialValue: getToStringValue(initialValue)
};
}
function updateWrapper$1(element, props) {
var node = element;
var value = getToStringValue(props.value);
var defaultValue = getToStringValue(props.defaultValue);
if (value != null) {
// Cast `value` to a string to ensure the value is set correctly. While
// browsers typically do this as necessary, jsdom doesn't.
var newValue = toString(value);
// To avoid side effects (such as losing text selection), only set value if changed
if (newValue !== node.value) {
node.value = newValue;
}
if (props.defaultValue == null && node.defaultValue !== newValue) {
node.defaultValue = newValue;
}
}
if (defaultValue != null) {
node.defaultValue = toString(defaultValue);
}
}
function postMountWrapper$3(element, props) {
var node = element;
// This is in postMount because we need access to the DOM node, which is not
// available until after the component has mounted.
var textContent = node.textContent;
// Only set node.value if textContent is equal to the expected
// initial value. In IE10/IE11 there is a bug where the placeholder attribute
// will populate textContent as well.
if (textContent === node._wrapperState.initialValue) {
node.value = textContent;
}
}
function restoreControlledState$3(element, props) {
// DOM component is still mounted; update
updateWrapper$1(element, props);
}
var HTML_NAMESPACE$1 = 'http://www.w3.org/1999/xhtml';
var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
var Namespaces = {
html: HTML_NAMESPACE$1,
mathml: MATH_NAMESPACE,
svg: SVG_NAMESPACE
};
// Assumes there is no parent namespace.
function getIntrinsicNamespace(type) {
switch (type) {
case 'svg':
return SVG_NAMESPACE;
case 'math':
return MATH_NAMESPACE;
default:
return HTML_NAMESPACE$1;
}
}
function getChildNamespace(parentNamespace, type) {
if (parentNamespace == null || parentNamespace === HTML_NAMESPACE$1) {
// No (or default) parent namespace: potential entry point.
return getIntrinsicNamespace(type);
}
if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') {
// We're leaving SVG.
return HTML_NAMESPACE$1;
}
// By default, pass namespace below.
return parentNamespace;
}
/* globals MSApp */
/**
* Create a function which has 'unsafe' privileges (required by windows8 apps)
*/
var createMicrosoftUnsafeLocalFunction = function (func) {
if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {
return function (arg0, arg1, arg2, arg3) {
MSApp.execUnsafeLocalFunction(function () {
return func(arg0, arg1, arg2, arg3);
});
};
} else {
return func;
}
};
// SVG temp container for IE lacking innerHTML
var reusableSVGContainer = void 0;
/**
* Set the innerHTML property of a node
*
* @param {DOMElement} node
* @param {string} html
* @internal
*/
var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) {
// IE does not have innerHTML for SVG nodes, so instead we inject the
// new markup in a temp node and then move the child nodes across into
// the target node
if (node.namespaceURI === Namespaces.svg && !('innerHTML' in node)) {
reusableSVGContainer = reusableSVGContainer || document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>';
var svgNode = reusableSVGContainer.firstChild;
while (node.firstChild) {
node.removeChild(node.firstChild);
}
while (svgNode.firstChild) {
node.appendChild(svgNode.firstChild);
}
} else {
node.innerHTML = html;
}
});
/**
* Set the textContent property of a node. For text updates, it's faster
* to set the `nodeValue` of the Text node directly instead of using
* `.textContent` which will remove the existing node and create a new one.
*
* @param {DOMElement} node
* @param {string} text
* @internal
*/
var setTextContent = function (node, text) {
if (text) {
var firstChild = node.firstChild;
if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE) {
firstChild.nodeValue = text;
return;
}
}
node.textContent = text;
};
// List derived from Gecko source code:
/**
* CSS properties which accept numbers but are not in units of "px".
*/
var isUnitlessNumber = {
animationIterationCount: true,
borderImageOutset: true,
borderImageSlice: true,
borderImageWidth: true,
boxFlex: true,
boxFlexGroup: true,
boxOrdinalGroup: true,
columnCount: true,
columns: true,
flex: true,
flexGrow: true,
flexPositive: true,
flexShrink: true,
flexNegative: true,
flexOrder: true,
gridArea: true,
gridRow: true,
gridRowEnd: true,
gridRowSpan: true,
gridRowStart: true,
gridColumn: true,
gridColumnEnd: true,
gridColumnSpan: true,
gridColumnStart: true,
fontWeight: true,
lineClamp: true,
lineHeight: true,
opacity: true,
order: true,
orphans: true,
tabSize: true,
widows: true,
zIndex: true,
zoom: true,
// SVG-related properties
fillOpacity: true,
floodOpacity: true,
stopOpacity: true,
strokeDasharray: true,
strokeDashoffset: true,
strokeMiterlimit: true,
strokeOpacity: true,
strokeWidth: true
};
/**
* @param {string} prefix vendor-specific prefix, eg: Webkit
* @param {string} key style name, eg: transitionDuration
* @return {string} style name prefixed with `prefix`, properly camelCased, eg:
* WebkitTransitionDuration
*/
function prefixKey(prefix, key) {
return prefix + key.charAt(0).toUpperCase() + key.substring(1);
}
/**
* Support style names that may come passed in prefixed by adding permutations
* of vendor prefixes.
*/
var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
Object.keys(isUnitlessNumber).forEach(function (prop) {
prefixes.forEach(function (prefix) {
isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
});
});
/**
* Convert a value into the proper css writable value. The style name `name`
* should be logical (no hyphens), as specified
* in `CSSProperty.isUnitlessNumber`.
*
* @param {string} name CSS property name such as `topMargin`.
* @param {*} value CSS property value such as `10px`.
* @return {string} Normalized style value with dimensions applied.
*/
function dangerousStyleValue(name, value, isCustomProperty) {
// Note that we've removed escapeTextForBrowser() calls here since the
// whole string will be escaped when the attribute is injected into
// the markup. If you provide unsafe user data here they can inject
// arbitrary CSS which may be problematic (I couldn't repro this):
// This is not an XSS hole but instead a potential CSS injection issue
// which has lead to a greater discussion about how we're going to
// trust URLs moving forward. See #2115901
var isEmpty = value == null || typeof value === 'boolean' || value === '';
if (isEmpty) {
return '';
}
if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) {
return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers
}
return ('' + value).trim();
}
/**
* Operations for dealing with CSS properties.
*/
/**
* This creates a string that is expected to be equivalent to the style
* attribute generated by server-side rendering. It by-passes warnings and
* security checks so it's not safe to use this value for anything other than
* comparison. It is only used in DEV for SSR validation.
*/
/**
* Sets the value for multiple styles on a node. If a value is specified as
* '' (empty string), the corresponding style property will be unset.
*
* @param {DOMElement} node
* @param {object} styles
*/
function setValueForStyles(node, styles) {
var style = node.style;
for (var styleName in styles) {
if (!styles.hasOwnProperty(styleName)) {
continue;
}
var isCustomProperty = styleName.indexOf('--') === 0;
var styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty);
if (styleName === 'float') {
styleName = 'cssFloat';
}
if (isCustomProperty) {
style.setProperty(styleName, styleValue);
} else {
style[styleName] = styleValue;
}
}
}
/**
* When mixing shorthand and longhand property names, we warn during updates if
* we expect an incorrect result to occur. In particular, we warn for:
*
* Updating a shorthand property (longhand gets overwritten):
* {font: 'foo', fontVariant: 'bar'} -> {font: 'baz', fontVariant: 'bar'}
* becomes .style.font = 'baz'
* Removing a shorthand property (longhand gets lost too):
* {font: 'foo', fontVariant: 'bar'} -> {fontVariant: 'bar'}
* becomes .style.font = ''
* Removing a longhand property (should revert to shorthand; doesn't):
* {font: 'foo', fontVariant: 'bar'} -> {font: 'foo'}
* becomes .style.fontVariant = ''
*/
// For HTML, certain tags should omit their close tag. We keep a whitelist for
// those special-case tags.
var omittedCloseTags = {
area: true,
base: true,
br: true,
col: true,
embed: true,
hr: true,
img: true,
input: true,
keygen: true,
link: true,
meta: true,
param: true,
source: true,
track: true,
wbr: true
// NOTE: menuitem's close tag should be omitted, but that causes problems.
};
// For HTML, certain tags cannot have children. This has the same purpose as
// `omittedCloseTags` except that `menuitem` should still have its closing tag.
var voidElementTags = _assign({
menuitem: true
}, omittedCloseTags);
// TODO: We can remove this if we add invariantWithStack()
// or add stack by default to invariants where possible.
var HTML$1 = '__html';
function assertValidProps(tag, props) {
if (!props) {
return;
}
// Note the use of `==` which checks for null or undefined.
if (voidElementTags[tag]) {
!(props.children == null && props.dangerouslySetInnerHTML == null) ? reactProdInvariant('137', tag, '') : void 0;
}
if (props.dangerouslySetInnerHTML != null) {
!(props.children == null) ? reactProdInvariant('60') : void 0;
!(typeof props.dangerouslySetInnerHTML === 'object' && HTML$1 in props.dangerouslySetInnerHTML) ? reactProdInvariant('61') : void 0;
}
!(props.style == null || typeof props.style === 'object') ? reactProdInvariant('62', '') : void 0;
}
function isCustomComponent(tagName, props) {
if (tagName.indexOf('-') === -1) {
return typeof props.is === 'string';
}
switch (tagName) {
// These are reserved SVG and MathML elements.
// We don't mind this whitelist too much because we expect it to never grow.
// The alternative is to track the namespace in a few places which is convoluted.
case 'annotation-xml':
case 'color-profile':
case 'font-face':
case 'font-face-src':
case 'font-face-uri':
case 'font-face-format':
case 'font-face-name':
case 'missing-glyph':
return false;
default:
return true;
}
}
// When adding attributes to the HTML or SVG whitelist, be sure to
// also add them to this module to ensure casing and incorrect name
// warnings.
// TODO: direct imports like some-package/src/* are bad. Fix me.
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 HTML_NAMESPACE = Namespaces.html;
function ensureListeningTo(rootContainerElement, registrationName) {
var isDocumentOrFragment = rootContainerElement.nodeType === DOCUMENT_NODE || rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE;
var doc = isDocumentOrFragment ? rootContainerElement : rootContainerElement.ownerDocument;
listenTo(registrationName, doc);
}
function getOwnerDocumentFromRootContainer(rootContainerElement) {
return rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument;
}
function noop() {}
function trapClickOnNonInteractiveElement(node) {
// Mobile Safari does not fire properly bubble click events on
// non-interactive elements, which means delegated click listeners do not
// fire. The workaround for this bug involves attaching an empty click
// listener on the target node.
// Just set it using the onclick property so that we don't have to manage any
// bookkeeping for it. Not sure if we need to clear it when the listener is
// removed.
// TODO: Only do this for the relevant Safaris maybe?
node.onclick = noop;
}
function setInitialDOMProperties(tag, domElement, rootContainerElement, nextProps, isCustomComponentTag) {
for (var propKey in nextProps) {
if (!nextProps.hasOwnProperty(propKey)) {
continue;
}
var nextProp = nextProps[propKey];
if (propKey === STYLE$1) {
setValueForStyles(domElement, nextProp);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
var nextHtml = nextProp ? nextProp[HTML] : undefined;
if (nextHtml != null) {
setInnerHTML(domElement, nextHtml);
}
} else if (propKey === CHILDREN) {
if (typeof nextProp === 'string') {
// Avoid setting initial textContent when the text is empty. In IE11 setting
// textContent on a <textarea> will cause the placeholder to not
// show within the <textarea> until it has been focused and blurred again.
var canSetTextContent = tag !== 'textarea' || nextProp !== '';
if (canSetTextContent) {
setTextContent(domElement, nextProp);
}
} else if (typeof nextProp === 'number') {
setTextContent(domElement, '' + nextProp);
}
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) {
// Noop
} else if (propKey === AUTOFOCUS) {
// We polyfill it separately on the client during commit.
// We could have excluded it in the property list instead of
// adding a special case here, but then it wouldn't be emitted
// on server rendering (but we *do* want to emit it in SSR).
} else if (registrationNameModules.hasOwnProperty(propKey)) {
if (nextProp != null) {
ensureListeningTo(rootContainerElement, propKey);
}
} else if (nextProp != null) {
setValueForProperty(domElement, propKey, nextProp, isCustomComponentTag);
}
}
}
function updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag) {
// TODO: Handle wasCustomComponentTag
for (var i = 0; i < updatePayload.length; i += 2) {
var propKey = updatePayload[i];
var propValue = updatePayload[i + 1];
if (propKey === STYLE$1) {
setValueForStyles(domElement, propValue);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
setInnerHTML(domElement, propValue);
} else if (propKey === CHILDREN) {
setTextContent(domElement, propValue);
} else {
setValueForProperty(domElement, propKey, propValue, isCustomComponentTag);
}
}
}
function createElement(type, props, rootContainerElement, parentNamespace) {
var ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement);
var domElement = void 0;
var namespaceURI = parentNamespace;
if (namespaceURI === HTML_NAMESPACE) {
namespaceURI = getIntrinsicNamespace(type);
}
if (namespaceURI === HTML_NAMESPACE) {
if (type === 'script') {
// Create the script via .innerHTML so its "parser-inserted" flag is
// set to true and it does not execute
var div = ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', 'div');
div.innerHTML = '<script><' + '/script>'; // eslint-disable-line
// This is guaranteed to yield a script element.
var firstChild = div.firstChild;
domElement = div.removeChild(firstChild);
} else if (typeof props.is === 'string') {
// $FlowIssue `createElement` should be updated for Web Components
domElement = ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', type, { is: props.is });
} else {
// Separate else branch instead of using `props.is || undefined` above because of a Firefox bug.
domElement = ownerDocument.createElementNS('http://www.w3.org/1999/xhtml', type);
// Normally attributes are assigned in `setInitialDOMProperties`, however the `multiple` and `size`
// attributes on `select`s needs to be added before `option`s are inserted.
// This prevents:
// - a bug where the `select` does not scroll to the correct option because singular
// `select` elements automatically pick the first item #13222
// - a bug where the `select` set the first item as selected despite the `size` attribute #14239
if (type === 'select') {
var node = domElement;
if (props.multiple) {
node.multiple = true;
} else if (props.size) {
// Setting a size greater than 1 causes a select to behave like `multiple=true`, where
// it is possible that no option is selected.
//
// This is only necessary when a select in "single selection mode".
node.size = props.size;
}
}
}
} else {
domElement = ownerDocument.createElementNS(namespaceURI, type);
}
return domElement;
}
function createTextNode(text, rootContainerElement) {
return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(text);
}
function setInitialProperties(domElement, tag, rawProps, rootContainerElement) {
var isCustomComponentTag = isCustomComponent(tag, rawProps);
var props = void 0;
switch (tag) {
case 'iframe':
case 'object':
trapBubbledEvent(TOP_LOAD, domElement);
props = rawProps;
break;
case 'video':
case 'audio':
// Create listener for each media event
for (var i = 0; i < mediaEventTypes.length; i++) {
trapBubbledEvent(mediaEventTypes[i], domElement);
}
props = rawProps;
break;
case 'source':
trapBubbledEvent(TOP_ERROR, domElement);
props = rawProps;
break;
case 'img':
case 'image':
case 'link':
trapBubbledEvent(TOP_ERROR, domElement);
trapBubbledEvent(TOP_LOAD, domElement);
props = rawProps;
break;
case 'form':
trapBubbledEvent(TOP_RESET, domElement);
trapBubbledEvent(TOP_SUBMIT, domElement);
props = rawProps;
break;
case 'details':
trapBubbledEvent(TOP_TOGGLE, domElement);
props = rawProps;
break;
case 'input':
initWrapperState(domElement, rawProps);
props = getHostProps(domElement, rawProps);
trapBubbledEvent(TOP_INVALID, domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange');
break;
case 'option':
props = getHostProps$1(domElement, rawProps);
break;
case 'select':
initWrapperState$1(domElement, rawProps);
props = getHostProps$2(domElement, rawProps);
trapBubbledEvent(TOP_INVALID, domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange');
break;
case 'textarea':
initWrapperState$2(domElement, rawProps);
props = getHostProps$3(domElement, rawProps);
trapBubbledEvent(TOP_INVALID, domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange');
break;
default:
props = rawProps;
}
assertValidProps(tag, props);
setInitialDOMProperties(tag, domElement, rootContainerElement, props, isCustomComponentTag);
switch (tag) {
case 'input':
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
track(domElement);
postMountWrapper(domElement, rawProps, false);
break;
case 'textarea':
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
track(domElement);
postMountWrapper$3(domElement, rawProps);
break;
case 'option':
postMountWrapper$1(domElement, rawProps);
break;
case 'select':
postMountWrapper$2(domElement, rawProps);
break;
default:
if (typeof props.onClick === 'function') {
// TODO: This cast may not be sound for SVG, MathML or custom elements.
trapClickOnNonInteractiveElement(domElement);
}
break;
}
}
// Calculate the diff between the two objects.
function diffProperties(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) {
var updatePayload = null;
var lastProps = void 0;
var nextProps = void 0;
switch (tag) {
case 'input':
lastProps = getHostProps(domElement, lastRawProps);
nextProps = getHostProps(domElement, nextRawProps);
updatePayload = [];
break;
case 'option':
lastProps = getHostProps$1(domElement, lastRawProps);
nextProps = getHostProps$1(domElement, nextRawProps);
updatePayload = [];
break;
case 'select':
lastProps = getHostProps$2(domElement, lastRawProps);
nextProps = getHostProps$2(domElement, nextRawProps);
updatePayload = [];
break;
case 'textarea':
lastProps = getHostProps$3(domElement, lastRawProps);
nextProps = getHostProps$3(domElement, nextRawProps);
updatePayload = [];
break;
default:
lastProps = lastRawProps;
nextProps = nextRawProps;
if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') {
// TODO: This cast may not be sound for SVG, MathML or custom elements.
trapClickOnNonInteractiveElement(domElement);
}
break;
}
assertValidProps(tag, nextProps);
var propKey = void 0;
var styleName = void 0;
var styleUpdates = null;
for (propKey in lastProps) {
if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) {
continue;
}
if (propKey === STYLE$1) {
var lastStyle = lastProps[propKey];
for (styleName in lastStyle) {
if (lastStyle.hasOwnProperty(styleName)) {
if (!styleUpdates) {
styleUpdates = {};
}
styleUpdates[styleName] = '';
}
}
} else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {
// Noop. This is handled by the clear text mechanism.
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) {
// Noop
} else if (propKey === AUTOFOCUS) {
// Noop. It doesn't work on updates anyway.
} else if (registrationNameModules.hasOwnProperty(propKey)) {
// This is a special case. If any listener updates we need to ensure
// that the "current" fiber pointer gets updated so we need a commit
// to update this element.
if (!updatePayload) {
updatePayload = [];
}
} else {
// For all other deleted properties we add it to the queue. We use
// the whitelist in the commit phase instead.
(updatePayload = updatePayload || []).push(propKey, null);
}
}
for (propKey in nextProps) {
var nextProp = nextProps[propKey];
var lastProp = lastProps != null ? lastProps[propKey] : undefined;
if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) {
continue;
}
if (propKey === STYLE$1) {
if (lastProp) {
// Unset styles on `lastProp` but not on `nextProp`.
for (styleName in lastProp) {
if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) {
if (!styleUpdates) {
styleUpdates = {};
}
styleUpdates[styleName] = '';
}
}
// Update styles that changed since `lastProp`.
for (styleName in nextProp) {
if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) {
if (!styleUpdates) {
styleUpdates = {};
}
styleUpdates[styleName] = nextProp[styleName];
}
}
} else {
// Relies on `updateStylesByID` not mutating `styleUpdates`.
if (!styleUpdates) {
if (!updatePayload) {
updatePayload = [];
}
updatePayload.push(propKey, styleUpdates);
}
styleUpdates = nextProp;
}
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
var nextHtml = nextProp ? nextProp[HTML] : undefined;
var lastHtml = lastProp ? lastProp[HTML] : undefined;
if (nextHtml != null) {
if (lastHtml !== nextHtml) {
(updatePayload = updatePayload || []).push(propKey, '' + nextHtml);
}
} else {
// TODO: It might be too late to clear this if we have children
// inserted already.
}
} else if (propKey === CHILDREN) {
if (lastProp !== nextProp && (typeof nextProp === 'string' || typeof nextProp === 'number')) {
(updatePayload = updatePayload || []).push(propKey, '' + nextProp);
}
} else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING$1) {
// Noop
} else if (registrationNameModules.hasOwnProperty(propKey)) {
if (nextProp != null) {
// We eagerly listen to this even though we haven't committed yet.
ensureListeningTo(rootContainerElement, propKey);
}
if (!updatePayload && lastProp !== nextProp) {
// This is a special case. If any listener updates we need to ensure
// that the "current" props pointer gets updated so we need a commit
// to update this element.
updatePayload = [];
}
} else {
// For any other property we always add it to the queue and then we
// filter it out using the whitelist during the commit.
(updatePayload = updatePayload || []).push(propKey, nextProp);
}
}
if (styleUpdates) {
(updatePayload = updatePayload || []).push(STYLE$1, styleUpdates);
}
return updatePayload;
}
// Apply the diff.
function updateProperties(domElement, updatePayload, tag, lastRawProps, nextRawProps) {
// Update checked *before* name.
// In the middle of an update, it is possible to have multiple checked.
// When a checked radio tries to change name, browser makes another radio's checked false.
if (tag === 'input' && nextRawProps.type === 'radio' && nextRawProps.name != null) {
updateChecked(domElement, nextRawProps);
}
var wasCustomComponentTag = isCustomComponent(tag, lastRawProps);
var isCustomComponentTag = isCustomComponent(tag, nextRawProps);
// Apply the diff.
updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag);
// TODO: Ensure that an update gets scheduled if any of the special props
// changed.
switch (tag) {
case 'input':
// Update the wrapper around inputs *after* updating props. This has to
// happen after `updateDOMProperties`. Otherwise HTML5 input validations
// raise warnings and prevent the new value from being assigned.
updateWrapper(domElement, nextRawProps);
break;
case 'textarea':
updateWrapper$1(domElement, nextRawProps);
break;
case 'select':
// <select> value update needs to occur after <option> children
// reconciliation
postUpdateWrapper(domElement, nextRawProps);
break;
}
}
function diffHydratedProperties(domElement, tag, rawProps, parentNamespace, rootContainerElement) {
var isCustomComponentTag = void 0;
switch (tag) {
case 'iframe':
case 'object':
trapBubbledEvent(TOP_LOAD, domElement);
break;
case 'video':
case 'audio':
// Create listener for each media event
for (var i = 0; i < mediaEventTypes.length; i++) {
trapBubbledEvent(mediaEventTypes[i], domElement);
}
break;
case 'source':
trapBubbledEvent(TOP_ERROR, domElement);
break;
case 'img':
case 'image':
case 'link':
trapBubbledEvent(TOP_ERROR, domElement);
trapBubbledEvent(TOP_LOAD, domElement);
break;
case 'form':
trapBubbledEvent(TOP_RESET, domElement);
trapBubbledEvent(TOP_SUBMIT, domElement);
break;
case 'details':
trapBubbledEvent(TOP_TOGGLE, domElement);
break;
case 'input':
initWrapperState(domElement, rawProps);
trapBubbledEvent(TOP_INVALID, domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange');
break;
case 'option':
break;
case 'select':
initWrapperState$1(domElement, rawProps);
trapBubbledEvent(TOP_INVALID, domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange');
break;
case 'textarea':
initWrapperState$2(domElement, rawProps);
trapBubbledEvent(TOP_INVALID, domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange');
break;
}
assertValidProps(tag, rawProps);
var updatePayload = null;
for (var propKey in rawProps) {
if (!rawProps.hasOwnProperty(propKey)) {
continue;
}
var nextProp = rawProps[propKey];
if (propKey === CHILDREN) {
// For text content children we compare against textContent. This
// might match additional HTML that is hidden when we read it using
// textContent. E.g. "foo" will match "f<span>oo</span>" but that still
// satisfies our requirement. Our requirement is not to produce perfect
// HTML and attributes. Ideally we should preserve structure but it's
// ok not to if the visible content is still enough to indicate what
// even listeners these nodes might be wired up to.
// TODO: Warn if there is more than a single textNode as a child.
// TODO: Should we use domElement.firstChild.nodeValue to compare?
if (typeof nextProp === 'string') {
if (domElement.textContent !== nextProp) {
updatePayload = [CHILDREN, nextProp];
}
} else if (typeof nextProp === 'number') {
if (domElement.textContent !== '' + nextProp) {
updatePayload = [CHILDREN, '' + nextProp];
}
}
} else if (registrationNameModules.hasOwnProperty(propKey)) {
if (nextProp != null) {
ensureListeningTo(rootContainerElement, propKey);
}
} else {}
}
switch (tag) {
case 'input':
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
track(domElement);
postMountWrapper(domElement, rawProps, true);
break;
case 'textarea':
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
track(domElement);
postMountWrapper$3(domElement, rawProps);
break;
case 'select':
case 'option':
// For input and textarea we current always set the value property at
// post mount to force it to diverge from attributes. However, for
// option and select we don't quite do the same thing and select
// is not resilient to the DOM state changing so we don't do that here.
// TODO: Consider not doing this for input and textarea.
break;
default:
if (typeof rawProps.onClick === 'function') {
// TODO: This cast may not be sound for SVG, MathML or custom elements.
trapClickOnNonInteractiveElement(domElement);
}
break;
}
return updatePayload;
}
function diffHydratedText(textNode, text) {
var isDifferent = textNode.nodeValue !== text;
return isDifferent;
}
function restoreControlledState$1(domElement, tag, props) {
switch (tag) {
case 'input':
restoreControlledState(domElement, props);
return;
case 'textarea':
restoreControlledState$3(domElement, props);
return;
case 'select':
restoreControlledState$2(domElement, props);
return;
}
}
// TODO: direct imports like some-package/src/* are bad. Fix me.
var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
var _ReactInternals$Sched = ReactInternals$1.Scheduler;
var unstable_cancelCallback = _ReactInternals$Sched.unstable_cancelCallback;
var unstable_now = _ReactInternals$Sched.unstable_now;
var unstable_scheduleCallback = _ReactInternals$Sched.unstable_scheduleCallback;
var unstable_shouldYield = _ReactInternals$Sched.unstable_shouldYield;
var unstable_getFirstCallbackNode = _ReactInternals$Sched.unstable_getFirstCallbackNode;
var unstable_runWithPriority = _ReactInternals$Sched.unstable_runWithPriority;
var unstable_next = _ReactInternals$Sched.unstable_next;
var unstable_continueExecution = _ReactInternals$Sched.unstable_continueExecution;
var unstable_pauseExecution = _ReactInternals$Sched.unstable_pauseExecution;
var unstable_getCurrentPriorityLevel = _ReactInternals$Sched.unstable_getCurrentPriorityLevel;
var unstable_ImmediatePriority = _ReactInternals$Sched.unstable_ImmediatePriority;
var unstable_UserBlockingPriority = _ReactInternals$Sched.unstable_UserBlockingPriority;
var unstable_NormalPriority = _ReactInternals$Sched.unstable_NormalPriority;
var unstable_LowPriority = _ReactInternals$Sched.unstable_LowPriority;
var unstable_IdlePriority = _ReactInternals$Sched.unstable_IdlePriority;
// Renderers that don't support persistence
// can re-export everything from this module.
function shim() {
reactProdInvariant('270');
}
// Persistence (when unsupported)
var supportsPersistence = false;
var cloneInstance = shim;
var createContainerChildSet = shim;
var appendChildToContainerChildSet = shim;
var finalizeContainerChildren = shim;
var replaceContainerChildren = shim;
var cloneHiddenInstance = shim;
var cloneUnhiddenInstance = shim;
var createHiddenTextInstance = shim;
var SUSPENSE_START_DATA = '$';
var SUSPENSE_END_DATA = '/$';
var STYLE = 'style';
var eventsEnabled = null;
var selectionInformation = null;
function shouldAutoFocusHostComponent(type, props) {
switch (type) {
case 'button':
case 'input':
case 'select':
case 'textarea':
return !!props.autoFocus;
}
return false;
}
function getRootHostContext(rootContainerInstance) {
var type = void 0;
var namespace = void 0;
var nodeType = rootContainerInstance.nodeType;
switch (nodeType) {
case DOCUMENT_NODE:
case DOCUMENT_FRAGMENT_NODE:
{
type = nodeType === DOCUMENT_NODE ? '#document' : '#fragment';
var root = rootContainerInstance.documentElement;
namespace = root ? root.namespaceURI : getChildNamespace(null, '');
break;
}
default:
{
var container = nodeType === COMMENT_NODE ? rootContainerInstance.parentNode : rootContainerInstance;
var ownNamespace = container.namespaceURI || null;
type = container.tagName;
namespace = getChildNamespace(ownNamespace, type);
break;
}
}
return namespace;
}
function getChildHostContext(parentHostContext, type, rootContainerInstance) {
var parentNamespace = parentHostContext;
return getChildNamespace(parentNamespace, type);
}
function getPublicInstance(instance) {
return instance;
}
function prepareForCommit(containerInfo) {
eventsEnabled = isEnabled();
selectionInformation = getSelectionInformation();
setEnabled(false);
}
function resetAfterCommit(containerInfo) {
restoreSelection(selectionInformation);
selectionInformation = null;
setEnabled(eventsEnabled);
eventsEnabled = null;
}
function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) {
var parentNamespace = void 0;
{
parentNamespace = hostContext;
}
var domElement = createElement(type, props, rootContainerInstance, parentNamespace);
precacheFiberNode(internalInstanceHandle, domElement);
updateFiberProps(domElement, props);
return domElement;
}
function appendInitialChild(parentInstance, child) {
parentInstance.appendChild(child);
}
function finalizeInitialChildren(domElement, type, props, rootContainerInstance, hostContext) {
setInitialProperties(domElement, type, props, rootContainerInstance);
return shouldAutoFocusHostComponent(type, props);
}
function prepareUpdate(domElement, type, oldProps, newProps, rootContainerInstance, hostContext) {
return diffProperties(domElement, type, oldProps, newProps, rootContainerInstance);
}
function shouldSetTextContent(type, props) {
return type === 'textarea' || type === 'option' || type === 'noscript' || typeof props.children === 'string' || typeof props.children === 'number' || typeof props.dangerouslySetInnerHTML === 'object' && props.dangerouslySetInnerHTML !== null && props.dangerouslySetInnerHTML.__html != null;
}
function shouldDeprioritizeSubtree(type, props) {
return !!props.hidden;
}
function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) {
var textNode = createTextNode(text, rootContainerInstance);
precacheFiberNode(internalInstanceHandle, textNode);
return textNode;
}
var isPrimaryRenderer = true;
// This initialization code may run even on server environments
// if a component just imports ReactDOM (e.g. for findDOMNode).
// Some environments might not have setTimeout or clearTimeout.
var scheduleTimeout = typeof setTimeout === 'function' ? setTimeout : undefined;
var cancelTimeout = typeof clearTimeout === 'function' ? clearTimeout : undefined;
var noTimeout = -1;
var schedulePassiveEffects = unstable_scheduleCallback;
var cancelPassiveEffects = unstable_cancelCallback;
// -------------------
// Mutation
// -------------------
var supportsMutation = true;
function commitMount(domElement, type, newProps, internalInstanceHandle) {
// Despite the naming that might imply otherwise, this method only
// fires if there is an `Update` effect scheduled during mounting.
// This happens if `finalizeInitialChildren` returns `true` (which it
// does to implement the `autoFocus` attribute on the client). But
// there are also other cases when this might happen (such as patching
// up text content during hydration mismatch). So we'll check this again.
if (shouldAutoFocusHostComponent(type, newProps)) {
domElement.focus();
}
}
function commitUpdate(domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) {
// Update the props handle so that we know which props are the ones with
// with current event handlers.
updateFiberProps(domElement, newProps);
// Apply the diff to the DOM node.
updateProperties(domElement, updatePayload, type, oldProps, newProps);
}
function resetTextContent(domElement) {
setTextContent(domElement, '');
}
function commitTextUpdate(textInstance, oldText, newText) {
textInstance.nodeValue = newText;
}
function appendChild(parentInstance, child) {
parentInstance.appendChild(child);
}
function appendChildToContainer(container, child) {
var parentNode = void 0;
if (container.nodeType === COMMENT_NODE) {
parentNode = container.parentNode;
parentNode.insertBefore(child, container);
} else {
parentNode = container;
parentNode.appendChild(child);
}
// This container might be used for a portal.
// If something inside a portal is clicked, that click should bubble
// through the React tree. However, on Mobile Safari the click would
// never bubble through the *DOM* tree unless an ancestor with onclick
// event exists. So we wouldn't see it and dispatch it.
// This is why we ensure that non React root containers have inline onclick
// defined.
var reactRootContainer = container._reactRootContainer;
if ((reactRootContainer === null || reactRootContainer === undefined) && parentNode.onclick === null) {
// TODO: This cast may not be sound for SVG, MathML or custom elements.
trapClickOnNonInteractiveElement(parentNode);
}
}
function insertBefore(parentInstance, child, beforeChild) {
parentInstance.insertBefore(child, beforeChild);
}
function insertInContainerBefore(container, child, beforeChild) {
if (container.nodeType === COMMENT_NODE) {
container.parentNode.insertBefore(child, beforeChild);
} else {
container.insertBefore(child, beforeChild);
}
}
function removeChild(parentInstance, child) {
parentInstance.removeChild(child);
}
function removeChildFromContainer(container, child) {
if (container.nodeType === COMMENT_NODE) {
container.parentNode.removeChild(child);
} else {
container.removeChild(child);
}
}
function clearSuspenseBoundary(parentInstance, suspenseInstance) {
var node = suspenseInstance;
// Delete all nodes within this suspense boundary.
// There might be nested nodes so we need to keep track of how
// deep we are and only break out when we're back on top.
var depth = 0;
do {
var nextNode = node.nextSibling;
parentInstance.removeChild(node);
if (nextNode && nextNode.nodeType === COMMENT_NODE) {
var data = nextNode.data;
if (data === SUSPENSE_END_DATA) {
if (depth === 0) {
parentInstance.removeChild(nextNode);
return;
} else {
depth--;
}
} else if (data === SUSPENSE_START_DATA) {
depth++;
}
}
node = nextNode;
} while (node);
// TODO: Warn, we didn't find the end comment boundary.
}
function clearSuspenseBoundaryFromContainer(container, suspenseInstance) {
if (container.nodeType === COMMENT_NODE) {
clearSuspenseBoundary(container.parentNode, suspenseInstance);
} else if (container.nodeType === ELEMENT_NODE) {
clearSuspenseBoundary(container, suspenseInstance);
} else {
// Document nodes should never contain suspense boundaries.
}
}
function hideInstance(instance) {
// TODO: Does this work for all element types? What about MathML? Should we
// pass host context to this method?
instance = instance;
instance.style.display = 'none';
}
function hideTextInstance(textInstance) {
textInstance.nodeValue = '';
}
function unhideInstance(instance, props) {
instance = instance;
var styleProp = props[STYLE];
var display = styleProp !== undefined && styleProp !== null && styleProp.hasOwnProperty('display') ? styleProp.display : null;
instance.style.display = dangerousStyleValue('display', display);
}
function unhideTextInstance(textInstance, text) {
textInstance.nodeValue = text;
}
// -------------------
// Hydration
// -------------------
var supportsHydration = true;
function canHydrateInstance(instance, type, props) {
if (instance.nodeType !== ELEMENT_NODE || type.toLowerCase() !== instance.nodeName.toLowerCase()) {
return null;
}
// This has now been refined to an element node.
return instance;
}
function canHydrateTextInstance(instance, text) {
if (text === '' || instance.nodeType !== TEXT_NODE) {
// Empty strings are not parsed by HTML so there won't be a correct match here.
return null;
}
// This has now been refined to a text node.
return instance;
}
function canHydrateSuspenseInstance(instance) {
if (instance.nodeType !== COMMENT_NODE) {
// Empty strings are not parsed by HTML so there won't be a correct match here.
return null;
}
// This has now been refined to a suspense node.
return instance;
}
function getNextHydratableSibling(instance) {
var node = instance.nextSibling;
// Skip non-hydratable nodes.
while (node && node.nodeType !== ELEMENT_NODE && node.nodeType !== TEXT_NODE && (!enableSuspenseServerRenderer || node.nodeType !== COMMENT_NODE || node.data !== SUSPENSE_START_DATA)) {
node = node.nextSibling;
}
return node;
}
function getFirstHydratableChild(parentInstance) {
var next = parentInstance.firstChild;
// Skip non-hydratable nodes.
while (next && next.nodeType !== ELEMENT_NODE && next.nodeType !== TEXT_NODE && (!enableSuspenseServerRenderer || next.nodeType !== COMMENT_NODE || next.data !== SUSPENSE_START_DATA)) {
next = next.nextSibling;
}
return next;
}
function hydrateInstance(instance, type, props, rootContainerInstance, hostContext, internalInstanceHandle) {
precacheFiberNode(internalInstanceHandle, instance);
// TODO: Possibly defer this until the commit phase where all the events
// get attached.
updateFiberProps(instance, props);
var parentNamespace = void 0;
{
parentNamespace = hostContext;
}
return diffHydratedProperties(instance, type, props, parentNamespace, rootContainerInstance);
}
function hydrateTextInstance(textInstance, text, internalInstanceHandle) {
precacheFiberNode(internalInstanceHandle, textInstance);
return diffHydratedText(textInstance, text);
}
function getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance) {
var node = suspenseInstance.nextSibling;
// Skip past all nodes within this suspense boundary.
// There might be nested nodes so we need to keep track of how
// deep we are and only break out when we're back on top.
var depth = 0;
while (node) {
if (node.nodeType === COMMENT_NODE) {
var data = node.data;
if (data === SUSPENSE_END_DATA) {
if (depth === 0) {
return getNextHydratableSibling(node);
} else {
depth--;
}
} else if (data === SUSPENSE_START_DATA) {
depth++;
}
}
node = node.nextSibling;
}
// TODO: Warn, we didn't find the end comment boundary.
return null;
}
// Prefix measurements so that it's possible to filter them.
// Longer prefixes are hard to read in DevTools.
var reactEmoji = '\u269B';
var warningEmoji = '\u26D4';
var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function';
// Keep track of current fiber so that we know the path to unwind on pause.
// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them?
var currentFiber = null;
// If we're in the middle of user code, which fiber and method is it?
// Reusing `currentFiber` would be confusing for this because user code fiber
// can change during commit phase too, but we don't need to unwind it (since
// lifecycles in the commit phase don't resemble a tree).
var currentPhase = null;
var currentPhaseFiber = null;
// Did lifecycle hook schedule an update? This is often a performance problem,
// so we will keep track of it, and include it in the report.
// Track commits caused by cascading updates.
var isCommitting = false;
var hasScheduledUpdateInCurrentCommit = false;
var hasScheduledUpdateInCurrentPhase = false;
var commitCountInCurrentWorkLoop = 0;
var effectCountInCurrentCommit = 0;
var isWaitingForCallback = false;
// During commits, we only show a measurement once per method name
// to avoid stretch the commit phase with measurement overhead.
var labelsInCurrentCommit = new Set();
var formatMarkName = function (markName) {
return reactEmoji + ' ' + markName;
};
var formatLabel = function (label, warning) {
var prefix = warning ? warningEmoji + ' ' : reactEmoji + ' ';
var suffix = warning ? ' Warning: ' + warning : '';
return '' + prefix + label + suffix;
};
var beginMark = function (markName) {
performance.mark(formatMarkName(markName));
};
var clearMark = function (markName) {
performance.clearMarks(formatMarkName(markName));
};
var endMark = function (label, markName, warning) {
var formattedMarkName = formatMarkName(markName);
var formattedLabel = formatLabel(label, warning);
try {
performance.measure(formattedLabel, formattedMarkName);
} catch (err) {}
// If previous mark was missing for some reason, this will throw.
// This could only happen if React crashed in an unexpected place earlier.
// Don't pile on with more errors.
// Clear marks immediately to avoid growing buffer.
performance.clearMarks(formattedMarkName);
performance.clearMeasures(formattedLabel);
};
var getFiberMarkName = function (label, debugID) {
return label + ' (#' + debugID + ')';
};
var getFiberLabel = function (componentName, isMounted, phase) {
if (phase === null) {
// These are composite component total time measurements.
return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']';
} else {
// Composite component methods.
return componentName + '.' + phase;
}
};
var beginFiberMark = function (fiber, phase) {
var componentName = getComponentName(fiber.type) || 'Unknown';
var debugID = fiber._debugID;
var isMounted = fiber.alternate !== null;
var label = getFiberLabel(componentName, isMounted, phase);
if (isCommitting && labelsInCurrentCommit.has(label)) {
// During the commit phase, we don't show duplicate labels because
// there is a fixed overhead for every measurement, and we don't
// want to stretch the commit phase beyond necessary.
return false;
}
labelsInCurrentCommit.add(label);
var markName = getFiberMarkName(label, debugID);
beginMark(markName);
return true;
};
var clearFiberMark = function (fiber, phase) {
var componentName = getComponentName(fiber.type) || 'Unknown';
var debugID = fiber._debugID;
var isMounted = fiber.alternate !== null;
var label = getFiberLabel(componentName, isMounted, phase);
var markName = getFiberMarkName(label, debugID);
clearMark(markName);
};
var endFiberMark = function (fiber, phase, warning) {
var componentName = getComponentName(fiber.type) || 'Unknown';
var debugID = fiber._debugID;
var isMounted = fiber.alternate !== null;
var label = getFiberLabel(componentName, isMounted, phase);
var markName = getFiberMarkName(label, debugID);
endMark(label, markName, warning);
};
var shouldIgnoreFiber = function (fiber) {
// Host components should be skipped in the timeline.
// We could check typeof fiber.type, but does this work with RN?
switch (fiber.tag) {
case HostRoot:
case HostComponent:
case HostText:
case HostPortal:
case Fragment:
case ContextProvider:
case ContextConsumer:
case Mode:
return true;
default:
return false;
}
};
var clearPendingPhaseMeasurement = function () {
if (currentPhase !== null && currentPhaseFiber !== null) {
clearFiberMark(currentPhaseFiber, currentPhase);
}
currentPhaseFiber = null;
currentPhase = null;
hasScheduledUpdateInCurrentPhase = false;
};
var pauseTimers = function () {
// Stops all currently active measurements so that they can be resumed
// if we continue in a later deferred loop from the same unit of work.
var fiber = currentFiber;
while (fiber) {
if (fiber._debugIsCurrentlyTiming) {
endFiberMark(fiber, null, null);
}
fiber = fiber.return;
}
};
var resumeTimersRecursively = function (fiber) {
if (fiber.return !== null) {
resumeTimersRecursively(fiber.return);
}
if (fiber._debugIsCurrentlyTiming) {
beginFiberMark(fiber, null);
}
};
var resumeTimers = function () {
// Resumes all measurements that were active during the last deferred loop.
if (currentFiber !== null) {
resumeTimersRecursively(currentFiber);
}
};
function recordEffect() {
if (enableUserTimingAPI) {
effectCountInCurrentCommit++;
}
}
function recordScheduleUpdate() {
if (enableUserTimingAPI) {
if (isCommitting) {
hasScheduledUpdateInCurrentCommit = true;
}
if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') {
hasScheduledUpdateInCurrentPhase = true;
}
}
}
function startRequestCallbackTimer() {
if (enableUserTimingAPI) {
if (supportsUserTiming && !isWaitingForCallback) {
isWaitingForCallback = true;
beginMark('(Waiting for async callback...)');
}
}
}
function stopRequestCallbackTimer(didExpire, expirationTime) {
if (enableUserTimingAPI) {
if (supportsUserTiming) {
isWaitingForCallback = false;
var warning = didExpire ? 'React was blocked by main thread' : null;
endMark('(Waiting for async callback... will force flush in ' + expirationTime + ' ms)', '(Waiting for async callback...)', warning);
}
}
}
function startWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// If we pause, this is the fiber to unwind from.
currentFiber = fiber;
if (!beginFiberMark(fiber, null)) {
return;
}
fiber._debugIsCurrentlyTiming = true;
}
}
function cancelWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// Remember we shouldn't complete measurement for this fiber.
// Otherwise flamechart will be deep even for small updates.
fiber._debugIsCurrentlyTiming = false;
clearFiberMark(fiber, null);
}
}
function stopWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// If we pause, its parent is the fiber to unwind from.
currentFiber = fiber.return;
if (!fiber._debugIsCurrentlyTiming) {
return;
}
fiber._debugIsCurrentlyTiming = false;
endFiberMark(fiber, null, null);
}
}
function stopFailedWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// If we pause, its parent is the fiber to unwind from.
currentFiber = fiber.return;
if (!fiber._debugIsCurrentlyTiming) {
return;
}
fiber._debugIsCurrentlyTiming = false;
var warning = fiber.tag === SuspenseComponent || fiber.tag === DehydratedSuspenseComponent ? 'Rendering was suspended' : 'An error was thrown inside this error boundary';
endFiberMark(fiber, null, warning);
}
}
function startPhaseTimer(fiber, phase) {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
clearPendingPhaseMeasurement();
if (!beginFiberMark(fiber, phase)) {
return;
}
currentPhaseFiber = fiber;
currentPhase = phase;
}
}
function stopPhaseTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
if (currentPhase !== null && currentPhaseFiber !== null) {
var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null;
endFiberMark(currentPhaseFiber, currentPhase, warning);
}
currentPhase = null;
currentPhaseFiber = null;
}
}
function startWorkLoopTimer(nextUnitOfWork) {
if (enableUserTimingAPI) {
currentFiber = nextUnitOfWork;
if (!supportsUserTiming) {
return;
}
commitCountInCurrentWorkLoop = 0;
// This is top level call.
// Any other measurements are performed within.
beginMark('(React Tree Reconciliation)');
// Resume any measurements that were in progress during the last loop.
resumeTimers();
}
}
function stopWorkLoopTimer(interruptedBy, didCompleteRoot) {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var warning = null;
if (interruptedBy !== null) {
if (interruptedBy.tag === HostRoot) {
warning = 'A top-level update interrupted the previous render';
} else {
var componentName = getComponentName(interruptedBy.type) || 'Unknown';
warning = 'An update to ' + componentName + ' interrupted the previous render';
}
} else if (commitCountInCurrentWorkLoop > 1) {
warning = 'There were cascading updates';
}
commitCountInCurrentWorkLoop = 0;
var label = didCompleteRoot ? '(React Tree Reconciliation: Completed Root)' : '(React Tree Reconciliation: Yielded)';
// Pause any measurements until the next loop.
pauseTimers();
endMark(label, '(React Tree Reconciliation)', warning);
}
}
function startCommitTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
isCommitting = true;
hasScheduledUpdateInCurrentCommit = false;
labelsInCurrentCommit.clear();
beginMark('(Committing Changes)');
}
}
function stopCommitTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var warning = null;
if (hasScheduledUpdateInCurrentCommit) {
warning = 'Lifecycle hook scheduled a cascading update';
} else if (commitCountInCurrentWorkLoop > 0) {
warning = 'Caused by a cascading update in earlier commit';
}
hasScheduledUpdateInCurrentCommit = false;
commitCountInCurrentWorkLoop++;
isCommitting = false;
labelsInCurrentCommit.clear();
endMark('(Committing Changes)', '(Committing Changes)', warning);
}
}
function startCommitSnapshotEffectsTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
effectCountInCurrentCommit = 0;
beginMark('(Committing Snapshot Effects)');
}
}
function stopCommitSnapshotEffectsTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var count = effectCountInCurrentCommit;
effectCountInCurrentCommit = 0;
endMark('(Committing Snapshot Effects: ' + count + ' Total)', '(Committing Snapshot Effects)', null);
}
}
function startCommitHostEffectsTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
effectCountInCurrentCommit = 0;
beginMark('(Committing Host Effects)');
}
}
function stopCommitHostEffectsTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var count = effectCountInCurrentCommit;
effectCountInCurrentCommit = 0;
endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null);
}
}
function startCommitLifeCyclesTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
effectCountInCurrentCommit = 0;
beginMark('(Calling Lifecycle Methods)');
}
}
function stopCommitLifeCyclesTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var count = effectCountInCurrentCommit;
effectCountInCurrentCommit = 0;
endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null);
}
}
var valueStack = [];
var index = -1;
function createCursor(defaultValue) {
return {
current: defaultValue
};
}
function pop(cursor, fiber) {
if (index < 0) {
return;
}
cursor.current = valueStack[index];
valueStack[index] = null;
index--;
}
function push(cursor, value, fiber) {
index++;
valueStack[index] = cursor.current;
cursor.current = value;
}
var emptyContextObject = {};
// A cursor to the current merged context object on the stack.
var contextStackCursor = createCursor(emptyContextObject);
// A cursor to a boolean indicating whether the context has changed.
var didPerformWorkStackCursor = createCursor(false);
// Keep track of the previous context object that was on the stack.
// We use this to get access to the parent context after we have already
// pushed the next context provider, and now need to merge their contexts.
var previousContext = emptyContextObject;
function getUnmaskedContext(workInProgress, Component, didPushOwnContextIfProvider) {
if (didPushOwnContextIfProvider && isContextProvider(Component)) {
// If the fiber is a context provider itself, when we read its context
// we may have already pushed its own child context on the stack. A context
// provider should not "see" its own child context. Therefore we read the
// previous (parent) context instead for a context provider.
return previousContext;
}
return contextStackCursor.current;
}
function cacheContext(workInProgress, unmaskedContext, maskedContext) {
var instance = workInProgress.stateNode;
instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext;
instance.__reactInternalMemoizedMaskedChildContext = maskedContext;
}
function getMaskedContext(workInProgress, unmaskedContext) {
var type = workInProgress.type;
var contextTypes = type.contextTypes;
if (!contextTypes) {
return emptyContextObject;
}
// Avoid recreating masked context unless unmasked context has changed.
// Failing to do this will result in unnecessary calls to componentWillReceiveProps.
// This may trigger infinite loops if componentWillReceiveProps calls setState.
var instance = workInProgress.stateNode;
if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) {
return instance.__reactInternalMemoizedMaskedChildContext;
}
var context = {};
for (var key in contextTypes) {
context[key] = unmaskedContext[key];
}
if (instance) {
cacheContext(workInProgress, unmaskedContext, context);
}
return context;
}
function hasContextChanged() {
return didPerformWorkStackCursor.current;
}
function isContextProvider(type) {
var childContextTypes = type.childContextTypes;
return childContextTypes !== null && childContextTypes !== undefined;
}
function popContext(fiber) {
pop(didPerformWorkStackCursor, fiber);
pop(contextStackCursor, fiber);
}
function popTopLevelContextObject(fiber) {
pop(didPerformWorkStackCursor, fiber);
pop(contextStackCursor, fiber);
}
function pushTopLevelContextObject(fiber, context, didChange) {
!(contextStackCursor.current === emptyContextObject) ? reactProdInvariant('168') : void 0;
push(contextStackCursor, context, fiber);
push(didPerformWorkStackCursor, didChange, fiber);
}
function processChildContext(fiber, type, parentContext) {
var instance = fiber.stateNode;
var childContextTypes = type.childContextTypes;
// TODO (bvaughn) Replace this behavior with an invariant() in the future.
// It has only been added in Fiber to match the (unintentional) behavior in Stack.
if (typeof instance.getChildContext !== 'function') {
return parentContext;
}
var childContext = void 0;
startPhaseTimer(fiber, 'getChildContext');
childContext = instance.getChildContext();
stopPhaseTimer();
for (var contextKey in childContext) {
!(contextKey in childContextTypes) ? reactProdInvariant('108', getComponentName(type) || 'Unknown', contextKey) : void 0;
}
return _assign({}, parentContext, childContext);
}
function pushContextProvider(workInProgress) {
var instance = workInProgress.stateNode;
// We push the context as early as possible to ensure stack integrity.
// If the instance does not exist yet, we will push null at first,
// and replace it on the stack later when invalidating the context.
var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyContextObject;
// Remember the parent context so we can merge with it later.
// Inherit the parent's did-perform-work value to avoid inadvertently blocking updates.
previousContext = contextStackCursor.current;
push(contextStackCursor, memoizedMergedChildContext, workInProgress);
push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress);
return true;
}
function invalidateContextProvider(workInProgress, type, didChange) {
var instance = workInProgress.stateNode;
!instance ? reactProdInvariant('169') : void 0;
if (didChange) {
// Merge parent and own context.
// Skip this if we're not updating due to sCU.
// This avoids unnecessarily recomputing memoized values.
var mergedContext = processChildContext(workInProgress, type, previousContext);
instance.__reactInternalMemoizedMergedChildContext = mergedContext;
// Replace the old (or empty) context with the new one.
// It is important to unwind the context in the reverse order.
pop(didPerformWorkStackCursor, workInProgress);
pop(contextStackCursor, workInProgress);
// Now push the new context and mark that it has changed.
push(contextStackCursor, mergedContext, workInProgress);
push(didPerformWorkStackCursor, didChange, workInProgress);
} else {
pop(didPerformWorkStackCursor, workInProgress);
push(didPerformWorkStackCursor, didChange, workInProgress);
}
}
function findCurrentUnmaskedContext(fiber) {
// Currently this is only used with renderSubtreeIntoContainer; not sure if it
// makes sense elsewhere
!(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? reactProdInvariant('170') : void 0;
var node = fiber;
do {
switch (node.tag) {
case HostRoot:
return node.stateNode.context;
case ClassComponent:
{
var Component = node.type;
if (isContextProvider(Component)) {
return node.stateNode.__reactInternalMemoizedMergedChildContext;
}
break;
}
}
node = node.return;
} while (node !== null);
reactProdInvariant('171');
}
var onCommitFiberRoot = null;
var onCommitFiberUnmount = null;
function catchErrors(fn) {
return function (arg) {
try {
return fn(arg);
} catch (err) {
}
};
}
var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined';
function injectInternals(internals) {
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
// No DevTools
return false;
}
var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook.isDisabled) {
// This isn't a real property on the hook, but it can be set to opt out
// of DevTools integration and associated warnings and logs.
return true;
}
if (!hook.supportsFiber) {
return true;
}
try {
var rendererID = hook.inject(internals);
// We have successfully injected, so now it is safe to set up hooks.
onCommitFiberRoot = catchErrors(function (root) {
return hook.onCommitFiberRoot(rendererID, root);
});
onCommitFiberUnmount = catchErrors(function (fiber) {
return hook.onCommitFiberUnmount(rendererID, fiber);
});
} catch (err) {
// Catch all errors because it is unsafe to throw during initialization.
}
// DevTools exists
return true;
}
function onCommitRoot(root) {
if (typeof onCommitFiberRoot === 'function') {
onCommitFiberRoot(root);
}
}
function onCommitUnmount(fiber) {
if (typeof onCommitFiberUnmount === 'function') {
onCommitFiberUnmount(fiber);
}
}
// Max 31 bit integer. The max integer size in V8 for 32-bit systems.
// Math.pow(2, 30) - 1
// 0b111111111111111111111111111111
var maxSigned31BitInt = 1073741823;
var NoWork = 0;
var Never = 1;
var Sync = maxSigned31BitInt;
var UNIT_SIZE = 10;
var MAGIC_NUMBER_OFFSET = maxSigned31BitInt - 1;
// 1 unit of expiration time represents 10ms.
function msToExpirationTime(ms) {
// Always add an offset so that we don't clash with the magic number for NoWork.
return MAGIC_NUMBER_OFFSET - (ms / UNIT_SIZE | 0);
}
function expirationTimeToMs(expirationTime) {
return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE;
}
function ceiling(num, precision) {
return ((num / precision | 0) + 1) * precision;
}
function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) {
return MAGIC_NUMBER_OFFSET - ceiling(MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE);
}
var LOW_PRIORITY_EXPIRATION = 5000;
var LOW_PRIORITY_BATCH_SIZE = 250;
function computeAsyncExpiration(currentTime) {
return computeExpirationBucket(currentTime, LOW_PRIORITY_EXPIRATION, LOW_PRIORITY_BATCH_SIZE);
}
// We intentionally set a higher expiration time for interactive updates in
// dev than in production.
//
// If the main thread is being blocked so long that you hit the expiration,
// it's a problem that could be solved with better scheduling.
//
// People will be more likely to notice this and fix it with the long
// expiration time in development.
//
// In production we opt for better UX at the risk of masking scheduling
// problems, by expiring fast.
var HIGH_PRIORITY_EXPIRATION = 150;
var HIGH_PRIORITY_BATCH_SIZE = 100;
function computeInteractiveExpiration(currentTime) {
return computeExpirationBucket(currentTime, HIGH_PRIORITY_EXPIRATION, HIGH_PRIORITY_BATCH_SIZE);
}
var NoContext = 0;
var ConcurrentMode = 1;
var StrictMode = 2;
var ProfileMode = 4;
function FiberNode(tag, pendingProps, key, mode) {
// Instance
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
// Fiber
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0;
this.ref = null;
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.contextDependencies = null;
this.mode = mode;
// Effects
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
this.expirationTime = NoWork;
this.childExpirationTime = NoWork;
this.alternate = null;
if (enableProfilerTimer) {
// Note: The following is done to avoid a v8 performance cliff.
//
// Initializing the fields below to smis and later updating them with
// double values will cause Fibers to end up having separate shapes.
// This behavior/bug has something to do with Object.preventExtension().
// Fortunately this only impacts DEV builds.
// Unfortunately it makes React unusably slow for some applications.
// To work around this, initialize the fields below with doubles.
//
// Learn more about this here:
this.actualDuration = Number.NaN;
this.actualStartTime = Number.NaN;
this.selfBaseDuration = Number.NaN;
this.treeBaseDuration = Number.NaN;
// It's okay to replace the initial doubles with smis after initialization.
// This won't trigger the performance cliff mentioned above,
// and it simplifies other profiler code (including DevTools).
this.actualDuration = 0;
this.actualStartTime = -1;
this.selfBaseDuration = 0;
this.treeBaseDuration = 0;
}
}
// This is a constructor function, rather than a POJO constructor, still
// please ensure we do the following:
// 1) Nobody should add any instance methods on this. Instance methods can be
// more difficult to predict when they get optimized and they are almost
// never inlined properly in static compilers.
// 2) Nobody should rely on `instanceof Fiber` for type testing. We should
// always know when it is a fiber.
// 3) We might want to experiment with using numeric keys since they are easier
// to optimize in a non-JIT environment.
// 4) We can easily go from a constructor to a createFiber object literal if that
// is faster.
// 5) It should be easy to port this to a C struct and keep a C implementation
// compatible.
var createFiber = function (tag, pendingProps, key, mode) {
// $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
return new FiberNode(tag, pendingProps, key, mode);
};
function shouldConstruct(Component) {
var prototype = Component.prototype;
return !!(prototype && prototype.isReactComponent);
}
function isSimpleFunctionComponent(type) {
return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined;
}
function resolveLazyComponentTag(Component) {
if (typeof Component === 'function') {
return shouldConstruct(Component) ? ClassComponent : FunctionComponent;
} else if (Component !== undefined && Component !== null) {
var $$typeof = Component.$$typeof;
if ($$typeof === REACT_FORWARD_REF_TYPE) {
return ForwardRef;
}
if ($$typeof === REACT_MEMO_TYPE) {
return MemoComponent;
}
}
return IndeterminateComponent;
}
// This is used to create an alternate fiber to do work on.
function createWorkInProgress(current, pendingProps, expirationTime) {
var workInProgress = current.alternate;
if (workInProgress === null) {
// We use a double buffering pooling technique because we know that we'll
// only ever need at most two versions of a tree. We pool the "other" unused
// node that we're free to reuse. This is lazily created to avoid allocating
// extra objects for things that are never updated. It also allow us to
// reclaim the extra memory if needed.
workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
workInProgress.pendingProps = pendingProps;
// We already have an alternate.
// Reset the effect tag.
workInProgress.effectTag = NoEffect;
// The effect list is no longer valid.
workInProgress.nextEffect = null;
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
if (enableProfilerTimer) {
// We intentionally reset, rather than copy, actualDuration & actualStartTime.
// This prevents time from endlessly accumulating in new commits.
// This has the downside of resetting values for different priority renders,
// But works for yielding (the common case) and should support resuming.
workInProgress.actualDuration = 0;
workInProgress.actualStartTime = -1;
}
}
workInProgress.childExpirationTime = current.childExpirationTime;
workInProgress.expirationTime = current.expirationTime;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
workInProgress.contextDependencies = current.contextDependencies;
// These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
if (enableProfilerTimer) {
workInProgress.selfBaseDuration = current.selfBaseDuration;
workInProgress.treeBaseDuration = current.treeBaseDuration;
}
return workInProgress;
}
function createHostRootFiber(isConcurrent) {
var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext;
if (enableProfilerTimer && isDevToolsPresent) {
// Always collect profile timings when DevTools are present.
// This enables DevTools to start capturing timing at any point–
// Without some nodes in the tree having empty base times.
mode |= ProfileMode;
}
return createFiber(HostRoot, null, null, mode);
}
function createFiberFromTypeAndProps(type, // React$ElementType
key, pendingProps, owner, mode, expirationTime) {
var fiber = void 0;
var fiberTag = IndeterminateComponent;
// The resolved type is set if we know what the final type will be. I.e. it's not lazy.
var resolvedType = type;
if (typeof type === 'function') {
if (shouldConstruct(type)) {
fiberTag = ClassComponent;
}
} else if (typeof type === 'string') {
fiberTag = HostComponent;
} else {
getTag: switch (type) {
case REACT_FRAGMENT_TYPE:
return createFiberFromFragment(pendingProps.children, mode, expirationTime, key);
case REACT_CONCURRENT_MODE_TYPE:
return createFiberFromMode(pendingProps, mode | ConcurrentMode | StrictMode, expirationTime, key);
case REACT_STRICT_MODE_TYPE:
return createFiberFromMode(pendingProps, mode | StrictMode, expirationTime, key);
case REACT_PROFILER_TYPE:
return createFiberFromProfiler(pendingProps, mode, expirationTime, key);
case REACT_SUSPENSE_TYPE:
return createFiberFromSuspense(pendingProps, mode, expirationTime, key);
default:
{
if (typeof type === 'object' && type !== null) {
switch (type.$$typeof) {
case REACT_PROVIDER_TYPE:
fiberTag = ContextProvider;
break getTag;
case REACT_CONTEXT_TYPE:
// This is a consumer
fiberTag = ContextConsumer;
break getTag;
case REACT_FORWARD_REF_TYPE:
fiberTag = ForwardRef;
break getTag;
case REACT_MEMO_TYPE:
fiberTag = MemoComponent;
break getTag;
case REACT_LAZY_TYPE:
fiberTag = LazyComponent;
resolvedType = null;
break getTag;
}
}
var info = '';
reactProdInvariant('130', type == null ? type : typeof type, info);
}
}
}
fiber = createFiber(fiberTag, pendingProps, key, mode);
fiber.elementType = type;
fiber.type = resolvedType;
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromElement(element, mode, expirationTime) {
var owner = null;
var type = element.type;
var key = element.key;
var pendingProps = element.props;
var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime);
return fiber;
}
function createFiberFromFragment(elements, mode, expirationTime, key) {
var fiber = createFiber(Fragment, elements, key, mode);
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromProfiler(pendingProps, mode, expirationTime, key) {
var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode);
// TODO: The Profiler fiber shouldn't have a type. It has a tag.
fiber.elementType = REACT_PROFILER_TYPE;
fiber.type = REACT_PROFILER_TYPE;
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromMode(pendingProps, mode, expirationTime, key) {
var fiber = createFiber(Mode, pendingProps, key, mode);
// TODO: The Mode fiber shouldn't have a type. It has a tag.
var type = (mode & ConcurrentMode) === NoContext ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE;
fiber.elementType = type;
fiber.type = type;
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromSuspense(pendingProps, mode, expirationTime, key) {
var fiber = createFiber(SuspenseComponent, pendingProps, key, mode);
// TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag.
var type = REACT_SUSPENSE_TYPE;
fiber.elementType = type;
fiber.type = type;
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromText(content, mode, expirationTime) {
var fiber = createFiber(HostText, content, null, mode);
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromHostInstanceForDeletion() {
var fiber = createFiber(HostComponent, null, null, NoContext);
// TODO: These should not need a type.
fiber.elementType = 'DELETED';
fiber.type = 'DELETED';
return fiber;
}
function createFiberFromPortal(portal, mode, expirationTime) {
var pendingProps = portal.children !== null ? portal.children : [];
var fiber = createFiber(HostPortal, pendingProps, portal.key, mode);
fiber.expirationTime = expirationTime;
fiber.stateNode = {
containerInfo: portal.containerInfo,
pendingChildren: null, // Used by persistent updates
implementation: portal.implementation
};
return fiber;
}
// Used for stashing WIP properties to replay failed work in DEV.
var ReactInternals$2 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
var _ReactInternals$Sched$1 = ReactInternals$2.SchedulerTracing;
var __interactionsRef = _ReactInternals$Sched$1.__interactionsRef;
var __subscriberRef = _ReactInternals$Sched$1.__subscriberRef;
var unstable_clear = _ReactInternals$Sched$1.unstable_clear;
var unstable_getCurrent = _ReactInternals$Sched$1.unstable_getCurrent;
var unstable_getThreadID = _ReactInternals$Sched$1.unstable_getThreadID;
var unstable_subscribe = _ReactInternals$Sched$1.unstable_subscribe;
var unstable_trace = _ReactInternals$Sched$1.unstable_trace;
var unstable_unsubscribe = _ReactInternals$Sched$1.unstable_unsubscribe;
var unstable_wrap = _ReactInternals$Sched$1.unstable_wrap;
// TODO: This should be lifted into the renderer.
// The following attributes are only used by interaction tracing builds.
// They enable interactions to be associated with their async work,
// And expose interaction metadata to the React DevTools Profiler plugin.
// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled.
// Exported FiberRoot type includes all properties,
// To avoid requiring potentially error-prone :any casts throughout the project.
// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true).
// The types are defined separately within this file to ensure they stay in sync.
// (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.)
function createFiberRoot(containerInfo, isConcurrent, hydrate) {
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
var uninitializedFiber = createHostRootFiber(isConcurrent);
var root = void 0;
if (enableSchedulerTracing) {
root = {
current: uninitializedFiber,
containerInfo: containerInfo,
pendingChildren: null,
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
pingCache: null,
didError: false,
pendingCommitExpirationTime: NoWork,
finishedWork: null,
timeoutHandle: noTimeout,
context: null,
pendingContext: null,
hydrate: hydrate,
nextExpirationTimeToWorkOn: NoWork,
expirationTime: NoWork,
firstBatch: null,
nextScheduledRoot: null,
interactionThreadID: unstable_getThreadID(),
memoizedInteractions: new Set(),
pendingInteractionMap: new Map()
};
} else {
root = {
current: uninitializedFiber,
containerInfo: containerInfo,
pendingChildren: null,
pingCache: null,
earliestPendingTime: NoWork,
latestPendingTime: NoWork,
earliestSuspendedTime: NoWork,
latestSuspendedTime: NoWork,
latestPingedTime: NoWork,
didError: false,
pendingCommitExpirationTime: NoWork,
finishedWork: null,
timeoutHandle: noTimeout,
context: null,
pendingContext: null,
hydrate: hydrate,
nextExpirationTimeToWorkOn: NoWork,
expirationTime: NoWork,
firstBatch: null,
nextScheduledRoot: null
};
}
uninitializedFiber.stateNode = root;
// The reason for the way the Flow types are structured in this file,
// Is to avoid needing :any casts everywhere interaction tracing fields are used.
// Unfortunately that requires an :any cast for non-interaction tracing capable builds.
// $FlowFixMe Remove this :any cast and replace it with something better.
return root;
}
/**
* Forked from fbjs/warning:
*
* Only change is we use console.warn instead of console.error,
* and do nothing when 'console' is not supported.
* This really simplifies the code.
* ---
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
* paths. Removing the logging code for production environments will keep the
* same logic and follow the same code paths.
*/
// This lets us hook into Fiber to debug what it's doing.
// This is not part of the public API, not even for React DevTools.
// You may only inject a debugTool if you work on React Fiber itself.
// TODO: Offscreen updates should never suspend. However, a promise that
// suspended inside an offscreen subtree should be able to ping at the priority
// of the outer render.
function markPendingPriorityLevel(root, expirationTime) {
// If there's a gap between completing a failed root and retrying it,
// additional updates may be scheduled. Clear `didError`, in case the update
// is sufficient to fix the error.
root.didError = false;
// Update the latest and earliest pending times
var earliestPendingTime = root.earliestPendingTime;
if (earliestPendingTime === NoWork) {
// No other pending updates.
root.earliestPendingTime = root.latestPendingTime = expirationTime;
} else {
if (earliestPendingTime < expirationTime) {
// This is the earliest pending update.
root.earliestPendingTime = expirationTime;
} else {
var latestPendingTime = root.latestPendingTime;
if (latestPendingTime > expirationTime) {
// This is the latest pending update
root.latestPendingTime = expirationTime;
}
}
}
findNextExpirationTimeToWorkOn(expirationTime, root);
}
function markCommittedPriorityLevels(root, earliestRemainingTime) {
root.didError = false;
if (earliestRemainingTime === NoWork) {
// Fast path. There's no remaining work. Clear everything.
root.earliestPendingTime = NoWork;
root.latestPendingTime = NoWork;
root.earliestSuspendedTime = NoWork;
root.latestSuspendedTime = NoWork;
root.latestPingedTime = NoWork;
findNextExpirationTimeToWorkOn(NoWork, root);
return;
}
if (earliestRemainingTime < root.latestPingedTime) {
root.latestPingedTime = NoWork;
}
// Let's see if the previous latest known pending level was just flushed.
var latestPendingTime = root.latestPendingTime;
if (latestPendingTime !== NoWork) {
if (latestPendingTime > earliestRemainingTime) {
// We've flushed all the known pending levels.
root.earliestPendingTime = root.latestPendingTime = NoWork;
} else {
var earliestPendingTime = root.earliestPendingTime;
if (earliestPendingTime > earliestRemainingTime) {
// We've flushed the earliest known pending level. Set this to the
// latest pending time.
root.earliestPendingTime = root.latestPendingTime;
}
}
}
// Now let's handle the earliest remaining level in the whole tree. We need to
// decide whether to treat it as a pending level or as suspended. Check
// it falls within the range of known suspended levels.
var earliestSuspendedTime = root.earliestSuspendedTime;
if (earliestSuspendedTime === NoWork) {
// There's no suspended work. Treat the earliest remaining level as a
// pending level.
markPendingPriorityLevel(root, earliestRemainingTime);
findNextExpirationTimeToWorkOn(NoWork, root);
return;
}
var latestSuspendedTime = root.latestSuspendedTime;
if (earliestRemainingTime < latestSuspendedTime) {
// The earliest remaining level is later than all the suspended work. That
// means we've flushed all the suspended work.
root.earliestSuspendedTime = NoWork;
root.latestSuspendedTime = NoWork;
root.latestPingedTime = NoWork;
// There's no suspended work. Treat the earliest remaining level as a
// pending level.
markPendingPriorityLevel(root, earliestRemainingTime);
findNextExpirationTimeToWorkOn(NoWork, root);
return;
}
if (earliestRemainingTime > earliestSuspendedTime) {
// The earliest remaining time is earlier than all the suspended work.
// Treat it as a pending update.
markPendingPriorityLevel(root, earliestRemainingTime);
findNextExpirationTimeToWorkOn(NoWork, root);
return;
}
// The earliest remaining time falls within the range of known suspended
// levels. We should treat this as suspended work.
findNextExpirationTimeToWorkOn(NoWork, root);
}
function hasLowerPriorityWork(root, erroredExpirationTime) {
var latestPendingTime = root.latestPendingTime;
var latestSuspendedTime = root.latestSuspendedTime;
var latestPingedTime = root.latestPingedTime;
return latestPendingTime !== NoWork && latestPendingTime < erroredExpirationTime || latestSuspendedTime !== NoWork && latestSuspendedTime < erroredExpirationTime || latestPingedTime !== NoWork && latestPingedTime < erroredExpirationTime;
}
function isPriorityLevelSuspended(root, expirationTime) {
var earliestSuspendedTime = root.earliestSuspendedTime;
var latestSuspendedTime = root.latestSuspendedTime;
return earliestSuspendedTime !== NoWork && expirationTime <= earliestSuspendedTime && expirationTime >= latestSuspendedTime;
}
function markSuspendedPriorityLevel(root, suspendedTime) {
root.didError = false;
clearPing(root, suspendedTime);
// First, check the known pending levels and update them if needed.
var earliestPendingTime = root.earliestPendingTime;
var latestPendingTime = root.latestPendingTime;
if (earliestPendingTime === suspendedTime) {
if (latestPendingTime === suspendedTime) {
// Both known pending levels were suspended. Clear them.
root.earliestPendingTime = root.latestPendingTime = NoWork;
} else {
// The earliest pending level was suspended. Clear by setting it to the
// latest pending level.
root.earliestPendingTime = latestPendingTime;
}
} else if (latestPendingTime === suspendedTime) {
// The latest pending level was suspended. Clear by setting it to the
// latest pending level.
root.latestPendingTime = earliestPendingTime;
}
// Finally, update the known suspended levels.
var earliestSuspendedTime = root.earliestSuspendedTime;
var latestSuspendedTime = root.latestSuspendedTime;
if (earliestSuspendedTime === NoWork) {
// No other suspended levels.
root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime;
} else {
if (earliestSuspendedTime < suspendedTime) {
// This is the earliest suspended level.
root.earliestSuspendedTime = suspendedTime;
} else if (latestSuspendedTime > suspendedTime) {
// This is the latest suspended level
root.latestSuspendedTime = suspendedTime;
}
}
findNextExpirationTimeToWorkOn(suspendedTime, root);
}
function markPingedPriorityLevel(root, pingedTime) {
root.didError = false;
// TODO: When we add back resuming, we need to ensure the progressed work
// is thrown out and not reused during the restarted render. One way to
// invalidate the progressed work is to restart at expirationTime + 1.
var latestPingedTime = root.latestPingedTime;
if (latestPingedTime === NoWork || latestPingedTime > pingedTime) {
root.latestPingedTime = pingedTime;
}
findNextExpirationTimeToWorkOn(pingedTime, root);
}
function clearPing(root, completedTime) {
var latestPingedTime = root.latestPingedTime;
if (latestPingedTime >= completedTime) {
root.latestPingedTime = NoWork;
}
}
function findEarliestOutstandingPriorityLevel(root, renderExpirationTime) {
var earliestExpirationTime = renderExpirationTime;
var earliestPendingTime = root.earliestPendingTime;
var earliestSuspendedTime = root.earliestSuspendedTime;
if (earliestPendingTime > earliestExpirationTime) {
earliestExpirationTime = earliestPendingTime;
}
if (earliestSuspendedTime > earliestExpirationTime) {
earliestExpirationTime = earliestSuspendedTime;
}
return earliestExpirationTime;
}
function didExpireAtExpirationTime(root, currentTime) {
var expirationTime = root.expirationTime;
if (expirationTime !== NoWork && currentTime <= expirationTime) {
// The root has expired. Flush all work up to the current time.
root.nextExpirationTimeToWorkOn = currentTime;
}
}
function findNextExpirationTimeToWorkOn(completedExpirationTime, root) {
var earliestSuspendedTime = root.earliestSuspendedTime;
var latestSuspendedTime = root.latestSuspendedTime;
var earliestPendingTime = root.earliestPendingTime;
var latestPingedTime = root.latestPingedTime;
// Work on the earliest pending time. Failing that, work on the latest
// pinged time.
var nextExpirationTimeToWorkOn = earliestPendingTime !== NoWork ? earliestPendingTime : latestPingedTime;
// If there is no pending or pinged work, check if there's suspended work
// that's lower priority than what we just completed.
if (nextExpirationTimeToWorkOn === NoWork && (completedExpirationTime === NoWork || latestSuspendedTime < completedExpirationTime)) {
// The lowest priority suspended work is the work most likely to be
// committed next. Let's start rendering it again, so that if it times out,
// it's ready to commit.
nextExpirationTimeToWorkOn = latestSuspendedTime;
}
var expirationTime = nextExpirationTimeToWorkOn;
if (expirationTime !== NoWork && earliestSuspendedTime > expirationTime) {
// Expire using the earliest known expiration time.
expirationTime = earliestSuspendedTime;
}
root.nextExpirationTimeToWorkOn = nextExpirationTimeToWorkOn;
root.expirationTime = expirationTime;
}
function resolveDefaultProps(Component, baseProps) {
if (Component && Component.defaultProps) {
// Resolve default props. Taken from ReactElement
var props = _assign({}, baseProps);
var defaultProps = Component.defaultProps;
for (var propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
return props;
}
return baseProps;
}
function readLazyComponentType(lazyComponent) {
var status = lazyComponent._status;
var result = lazyComponent._result;
switch (status) {
case Resolved:
{
var Component = result;
return Component;
}
case Rejected:
{
var error = result;
throw error;
}
case Pending:
{
var thenable = result;
throw thenable;
}
default:
{
lazyComponent._status = Pending;
var ctor = lazyComponent._ctor;
var _thenable = ctor();
_thenable.then(function (moduleObject) {
if (lazyComponent._status === Pending) {
var defaultExport = moduleObject.default;
lazyComponent._status = Resolved;
lazyComponent._result = defaultExport;
}
}, function (error) {
if (lazyComponent._status === Pending) {
lazyComponent._status = Rejected;
lazyComponent._result = error;
}
});
// Handle synchronous thenables.
switch (lazyComponent._status) {
case Resolved:
return lazyComponent._result;
case Rejected:
throw lazyComponent._result;
}
lazyComponent._result = _thenable;
throw _thenable;
}
}
}
// React.Component uses a shared frozen object by default.
// We'll use it to determine whether we need to initialize legacy refs.
var emptyRefsObject = new React.Component().refs;
function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) {
var prevState = workInProgress.memoizedState;
var partialState = getDerivedStateFromProps(nextProps, prevState);
var memoizedState = partialState === null || partialState === undefined ? prevState : _assign({}, prevState, partialState);
workInProgress.memoizedState = memoizedState;
// Once the update queue is empty, persist the derived state onto the
// base state.
var updateQueue = workInProgress.updateQueue;
if (updateQueue !== null && workInProgress.expirationTime === NoWork) {
updateQueue.baseState = memoizedState;
}
}
var classComponentUpdater = {
isMounted: isMounted,
enqueueSetState: function (inst, payload, callback) {
var fiber = get(inst);
var currentTime = requestCurrentTime();
var expirationTime = computeExpirationForFiber(currentTime, fiber);
var update = createUpdate(expirationTime);
update.payload = payload;
if (callback !== undefined && callback !== null) {
update.callback = callback;
}
flushPassiveEffects();
enqueueUpdate(fiber, update);
scheduleWork(fiber, expirationTime);
},
enqueueReplaceState: function (inst, payload, callback) {
var fiber = get(inst);
var currentTime = requestCurrentTime();
var expirationTime = computeExpirationForFiber(currentTime, fiber);
var update = createUpdate(expirationTime);
update.tag = ReplaceState;
update.payload = payload;
if (callback !== undefined && callback !== null) {
update.callback = callback;
}
flushPassiveEffects();
enqueueUpdate(fiber, update);
scheduleWork(fiber, expirationTime);
},
enqueueForceUpdate: function (inst, callback) {
var fiber = get(inst);
var currentTime = requestCurrentTime();
var expirationTime = computeExpirationForFiber(currentTime, fiber);
var update = createUpdate(expirationTime);
update.tag = ForceUpdate;
if (callback !== undefined && callback !== null) {
update.callback = callback;
}
flushPassiveEffects();
enqueueUpdate(fiber, update);
scheduleWork(fiber, expirationTime);
}
};
function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) {
var instance = workInProgress.stateNode;
if (typeof instance.shouldComponentUpdate === 'function') {
startPhaseTimer(workInProgress, 'shouldComponentUpdate');
var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext);
stopPhaseTimer();
return shouldUpdate;
}
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState);
}
return true;
}
function adoptClassInstance(workInProgress, instance) {
instance.updater = classComponentUpdater;
workInProgress.stateNode = instance;
// The instance needs access to the fiber so that it can schedule updates
set(instance, workInProgress);
}
function constructClassInstance(workInProgress, ctor, props, renderExpirationTime) {
var isLegacyContextConsumer = false;
var unmaskedContext = emptyContextObject;
var context = null;
var contextType = ctor.contextType;
if (typeof contextType === 'object' && contextType !== null) {
context = readContext(contextType);
} else {
unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
var contextTypes = ctor.contextTypes;
isLegacyContextConsumer = contextTypes !== null && contextTypes !== undefined;
context = isLegacyContextConsumer ? getMaskedContext(workInProgress, unmaskedContext) : emptyContextObject;
}
// Instantiate twice to help detect side-effects.
var instance = new ctor(props, context);
var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null;
adoptClassInstance(workInProgress, instance);
if (isLegacyContextConsumer) {
cacheContext(workInProgress, unmaskedContext, context);
}
return instance;
}
function callComponentWillMount(workInProgress, instance) {
startPhaseTimer(workInProgress, 'componentWillMount');
var oldState = instance.state;
if (typeof instance.componentWillMount === 'function') {
instance.componentWillMount();
}
if (typeof instance.UNSAFE_componentWillMount === 'function') {
instance.UNSAFE_componentWillMount();
}
stopPhaseTimer();
if (oldState !== instance.state) {
classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
}
}
function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) {
var oldState = instance.state;
startPhaseTimer(workInProgress, 'componentWillReceiveProps');
if (typeof instance.componentWillReceiveProps === 'function') {
instance.componentWillReceiveProps(newProps, nextContext);
}
if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') {
instance.UNSAFE_componentWillReceiveProps(newProps, nextContext);
}
stopPhaseTimer();
if (instance.state !== oldState) {
classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
}
}
// Invokes the mount life-cycles on a previously never rendered instance.
function mountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) {
var instance = workInProgress.stateNode;
instance.props = newProps;
instance.state = workInProgress.memoizedState;
instance.refs = emptyRefsObject;
var contextType = ctor.contextType;
if (typeof contextType === 'object' && contextType !== null) {
instance.context = readContext(contextType);
} else {
var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
instance.context = getMaskedContext(workInProgress, unmaskedContext);
}
var updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime);
instance.state = workInProgress.memoizedState;
}
var getDerivedStateFromProps = ctor.getDerivedStateFromProps;
if (typeof getDerivedStateFromProps === 'function') {
applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps);
instance.state = workInProgress.memoizedState;
}
// In order to support react-lifecycles-compat polyfilled components,
// Unsafe lifecycles should not be invoked for components using the new APIs.
if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
callComponentWillMount(workInProgress, instance);
// If we had additional state updates during this life-cycle, let's
// process them now.
updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime);
instance.state = workInProgress.memoizedState;
}
}
if (typeof instance.componentDidMount === 'function') {
workInProgress.effectTag |= Update;
}
}
function resumeMountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) {
var instance = workInProgress.stateNode;
var oldProps = workInProgress.memoizedProps;
instance.props = oldProps;
var oldContext = instance.context;
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === 'object' && contextType !== null) {
nextContext = readContext(contextType);
} else {
var nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext);
}
var getDerivedStateFromProps = ctor.getDerivedStateFromProps;
var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function';
// Note: During these life-cycles, instance.props/instance.state are what
// ever the previously attempted to render - not the "current". However,
// during componentDidUpdate we pass the "current" props.
// In order to support react-lifecycles-compat polyfilled components,
// Unsafe lifecycles should not be invoked for components using the new APIs.
if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) {
if (oldProps !== newProps || oldContext !== nextContext) {
callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext);
}
}
resetHasForceUpdateBeforeProcessing();
var oldState = workInProgress.memoizedState;
var newState = instance.state = oldState;
var updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime);
newState = workInProgress.memoizedState;
}
if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) {
// If an update was already in progress, we should schedule an Update
// effect even though we're bailing out, so that cWU/cDU are called.
if (typeof instance.componentDidMount === 'function') {
workInProgress.effectTag |= Update;
}
return false;
}
if (typeof getDerivedStateFromProps === 'function') {
applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps);
newState = workInProgress.memoizedState;
}
var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext);
if (shouldUpdate) {
// In order to support react-lifecycles-compat polyfilled components,
// Unsafe lifecycles should not be invoked for components using the new APIs.
if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {
startPhaseTimer(workInProgress, 'componentWillMount');
if (typeof instance.componentWillMount === 'function') {
instance.componentWillMount();
}
if (typeof instance.UNSAFE_componentWillMount === 'function') {
instance.UNSAFE_componentWillMount();
}
stopPhaseTimer();
}
if (typeof instance.componentDidMount === 'function') {
workInProgress.effectTag |= Update;
}
} else {
// If an update was already in progress, we should schedule an Update
// effect even though we're bailing out, so that cWU/cDU are called.
if (typeof instance.componentDidMount === 'function') {
workInProgress.effectTag |= Update;
}
// If shouldComponentUpdate returned false, we should still update the
// memoized state to indicate that this work can be reused.
workInProgress.memoizedProps = newProps;
workInProgress.memoizedState = newState;
}
// Update the existing instance's state, props, and context pointers even
// if shouldComponentUpdate returns false.
instance.props = newProps;
instance.state = newState;
instance.context = nextContext;
return shouldUpdate;
}
// Invokes the update life-cycles and returns false if it shouldn't rerender.
function updateClassInstance(current, workInProgress, ctor, newProps, renderExpirationTime) {
var instance = workInProgress.stateNode;
var oldProps = workInProgress.memoizedProps;
instance.props = workInProgress.type === workInProgress.elementType ? oldProps : resolveDefaultProps(workInProgress.type, oldProps);
var oldContext = instance.context;
var contextType = ctor.contextType;
var nextContext = void 0;
if (typeof contextType === 'object' && contextType !== null) {
nextContext = readContext(contextType);
} else {
var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);
}
var getDerivedStateFromProps = ctor.getDerivedStateFromProps;
var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function';
// Note: During these life-cycles, instance.props/instance.state are what
// ever the previously attempted to render - not the "current". However,
// during componentDidUpdate we pass the "current" props.
// In order to support react-lifecycles-compat polyfilled components,
// Unsafe lifecycles should not be invoked for components using the new APIs.
if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) {
if (oldProps !== newProps || oldContext !== nextContext) {
callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext);
}
}
resetHasForceUpdateBeforeProcessing();
var oldState = workInProgress.memoizedState;
var newState = instance.state = oldState;
var updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime);
newState = workInProgress.memoizedState;
}
if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) {
// If an update was already in progress, we should schedule an Update
// effect even though we're bailing out, so that cWU/cDU are called.
if (typeof instance.componentDidUpdate === 'function') {
if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {
workInProgress.effectTag |= Update;
}
}
if (typeof instance.getSnapshotBeforeUpdate === 'function') {
if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {
workInProgress.effectTag |= Snapshot;
}
}
return false;
}
if (typeof getDerivedStateFromProps === 'function') {
applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps);
newState = workInProgress.memoizedState;
}
var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext);
if (shouldUpdate) {
// In order to support react-lifecycles-compat polyfilled components,
// Unsafe lifecycles should not be invoked for components using the new APIs.
if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function')) {
startPhaseTimer(workInProgress, 'componentWillUpdate');
if (typeof instance.componentWillUpdate === 'function') {
instance.componentWillUpdate(newProps, newState, nextContext);
}
if (typeof instance.UNSAFE_componentWillUpdate === 'function') {
instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext);
}
stopPhaseTimer();
}
if (typeof instance.componentDidUpdate === 'function') {
workInProgress.effectTag |= Update;
}
if (typeof instance.getSnapshotBeforeUpdate === 'function') {
workInProgress.effectTag |= Snapshot;
}
} else {
// If an update was already in progress, we should schedule an Update
// effect even though we're bailing out, so that cWU/cDU are called.
if (typeof instance.componentDidUpdate === 'function') {
if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {
workInProgress.effectTag |= Update;
}
}
if (typeof instance.getSnapshotBeforeUpdate === 'function') {
if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {
workInProgress.effectTag |= Snapshot;
}
}
// If shouldComponentUpdate returned false, we should still update the
// memoized props/state to indicate that this work can be reused.
workInProgress.memoizedProps = newProps;
workInProgress.memoizedState = newState;
}
// Update the existing instance's state, props, and context pointers even
// if shouldComponentUpdate returns false.
instance.props = newProps;
instance.state = newState;
instance.context = nextContext;
return shouldUpdate;
}
var isArray = Array.isArray;
function coerceRef(returnFiber, current$$1, element) {
var mixedRef = element.ref;
if (mixedRef !== null && typeof mixedRef !== 'function' && typeof mixedRef !== 'object') {
if (element._owner) {
var owner = element._owner;
var inst = void 0;
if (owner) {
var ownerFiber = owner;
!(ownerFiber.tag === ClassComponent) ? reactProdInvariant('309') : void 0;
inst = ownerFiber.stateNode;
}
!inst ? reactProdInvariant('147', mixedRef) : void 0;
var stringRef = '' + mixedRef;
// Check if previous string ref matches new string ref
if (current$$1 !== null && current$$1.ref !== null && typeof current$$1.ref === 'function' && current$$1.ref._stringRef === stringRef) {
return current$$1.ref;
}
var ref = function (value) {
var refs = inst.refs;
if (refs === emptyRefsObject) {
// This is a lazy pooled frozen object, so we need to initialize.
refs = inst.refs = {};
}
if (value === null) {
delete refs[stringRef];
} else {
refs[stringRef] = value;
}
};
ref._stringRef = stringRef;
return ref;
} else {
!(typeof mixedRef === 'string') ? reactProdInvariant('284') : void 0;
!element._owner ? reactProdInvariant('290', mixedRef) : void 0;
}
}
return mixedRef;
}
function throwOnInvalidObjectType(returnFiber, newChild) {
if (returnFiber.type !== 'textarea') {
var addendum = '';
reactProdInvariant('31', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum);
}
}
// This wrapper function exists because I expect to clone the code in each path
// to be able to optimize each path individually by branching early. This needs
// a compiler or we can do it manually. Helpers that don't need this branching
// live outside of this function.
function ChildReconciler(shouldTrackSideEffects) {
function deleteChild(returnFiber, childToDelete) {
if (!shouldTrackSideEffects) {
// Noop.
return;
}
// Deletions are added in reversed order so we add it to the front.
// At this point, the return fiber's effect list is empty except for
// deletions, so we can just append the deletion to the list. The remaining
// effects aren't added until the complete phase. Once we implement
// resuming, this may not be true.
var last = returnFiber.lastEffect;
if (last !== null) {
last.nextEffect = childToDelete;
returnFiber.lastEffect = childToDelete;
} else {
returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
}
childToDelete.nextEffect = null;
childToDelete.effectTag = Deletion;
}
function deleteRemainingChildren(returnFiber, currentFirstChild) {
if (!shouldTrackSideEffects) {
// Noop.
return null;
}
// TODO: For the shouldClone case, this could be micro-optimized a bit by
// assuming that after the first child we've already added everything.
var childToDelete = currentFirstChild;
while (childToDelete !== null) {
deleteChild(returnFiber, childToDelete);
childToDelete = childToDelete.sibling;
}
return null;
}
function mapRemainingChildren(returnFiber, currentFirstChild) {
// Add the remaining children to a temporary map so that we can find them by
// keys quickly. Implicit (null) keys get added to this set with their index
var existingChildren = new Map();
var existingChild = currentFirstChild;
while (existingChild !== null) {
if (existingChild.key !== null) {
existingChildren.set(existingChild.key, existingChild);
} else {
existingChildren.set(existingChild.index, existingChild);
}
existingChild = existingChild.sibling;
}
return existingChildren;
}
function useFiber(fiber, pendingProps, expirationTime) {
// We currently set sibling to null and index to 0 here because it is easy
// to forget to do before returning it. E.g. for the single child case.
var clone = createWorkInProgress(fiber, pendingProps, expirationTime);
clone.index = 0;
clone.sibling = null;
return clone;
}
function placeChild(newFiber, lastPlacedIndex, newIndex) {
newFiber.index = newIndex;
if (!shouldTrackSideEffects) {
// Noop.
return lastPlacedIndex;
}
var current$$1 = newFiber.alternate;
if (current$$1 !== null) {
var oldIndex = current$$1.index;
if (oldIndex < lastPlacedIndex) {
// This is a move.
newFiber.effectTag = Placement;
return lastPlacedIndex;
} else {
// This item can stay in place.
return oldIndex;
}
} else {
// This is an insertion.
newFiber.effectTag = Placement;
return lastPlacedIndex;
}
}
function placeSingleChild(newFiber) {
// This is simpler for the single child case. We only need to do a
// placement for inserting new children.
if (shouldTrackSideEffects && newFiber.alternate === null) {
newFiber.effectTag = Placement;
}
return newFiber;
}
function updateTextNode(returnFiber, current$$1, textContent, expirationTime) {
if (current$$1 === null || current$$1.tag !== HostText) {
// Insert
var created = createFiberFromText(textContent, returnFiber.mode, expirationTime);
created.return = returnFiber;
return created;
} else {
// Update
var existing = useFiber(current$$1, textContent, expirationTime);
existing.return = returnFiber;
return existing;
}
}
function updateElement(returnFiber, current$$1, element, expirationTime) {
if (current$$1 !== null && current$$1.elementType === element.type) {
// Move based on index
var existing = useFiber(current$$1, element.props, expirationTime);
existing.ref = coerceRef(returnFiber, current$$1, element);
existing.return = returnFiber;
return existing;
} else {
// Insert
var created = createFiberFromElement(element, returnFiber.mode, expirationTime);
created.ref = coerceRef(returnFiber, current$$1, element);
created.return = returnFiber;
return created;
}
}
function updatePortal(returnFiber, current$$1, portal, expirationTime) {
if (current$$1 === null || current$$1.tag !== HostPortal || current$$1.stateNode.containerInfo !== portal.containerInfo || current$$1.stateNode.implementation !== portal.implementation) {
// Insert
var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime);
created.return = returnFiber;
return created;
} else {
// Update
var existing = useFiber(current$$1, portal.children || [], expirationTime);
existing.return = returnFiber;
return existing;
}
}
function updateFragment(returnFiber, current$$1, fragment, expirationTime, key) {
if (current$$1 === null || current$$1.tag !== Fragment) {
// Insert
var created = createFiberFromFragment(fragment, returnFiber.mode, expirationTime, key);
created.return = returnFiber;
return created;
} else {
// Update
var existing = useFiber(current$$1, fragment, expirationTime);
existing.return = returnFiber;
return existing;
}
}
function createChild(returnFiber, newChild, expirationTime) {
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys. If the previous node is implicitly keyed
// we can continue to replace it without aborting even if it is not a text
// node.
var created = createFiberFromText('' + newChild, returnFiber.mode, expirationTime);
created.return = returnFiber;
return created;
}
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
{
var _created = createFiberFromElement(newChild, returnFiber.mode, expirationTime);
_created.ref = coerceRef(returnFiber, null, newChild);
_created.return = returnFiber;
return _created;
}
case REACT_PORTAL_TYPE:
{
var _created2 = createFiberFromPortal(newChild, returnFiber.mode, expirationTime);
_created2.return = returnFiber;
return _created2;
}
}
if (isArray(newChild) || getIteratorFn(newChild)) {
var _created3 = createFiberFromFragment(newChild, returnFiber.mode, expirationTime, null);
_created3.return = returnFiber;
return _created3;
}
throwOnInvalidObjectType(returnFiber, newChild);
}
return null;
}
function updateSlot(returnFiber, oldFiber, newChild, expirationTime) {
// Update the fiber if the keys match, otherwise return null.
var key = oldFiber !== null ? oldFiber.key : null;
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys. If the previous node is implicitly keyed
// we can continue to replace it without aborting even if it is not a text
// node.
if (key !== null) {
return null;
}
return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime);
}
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
{
if (newChild.key === key) {
if (newChild.type === REACT_FRAGMENT_TYPE) {
return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key);
}
return updateElement(returnFiber, oldFiber, newChild, expirationTime);
} else {
return null;
}
}
case REACT_PORTAL_TYPE:
{
if (newChild.key === key) {
return updatePortal(returnFiber, oldFiber, newChild, expirationTime);
} else {
return null;
}
}
}
if (isArray(newChild) || getIteratorFn(newChild)) {
if (key !== null) {
return null;
}
return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null);
}
throwOnInvalidObjectType(returnFiber, newChild);
}
return null;
}
function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) {
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys, so we neither have to check the old nor
// new node for the key. If both are text nodes, they match.
var matchedFiber = existingChildren.get(newIdx) || null;
return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime);
}
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
{
var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null;
if (newChild.type === REACT_FRAGMENT_TYPE) {
return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key);
}
return updateElement(returnFiber, _matchedFiber, newChild, expirationTime);
}
case REACT_PORTAL_TYPE:
{
var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null;
return updatePortal(returnFiber, _matchedFiber2, newChild, expirationTime);
}
}
if (isArray(newChild) || getIteratorFn(newChild)) {
var _matchedFiber3 = existingChildren.get(newIdx) || null;
return updateFragment(returnFiber, _matchedFiber3, newChild, expirationTime, null);
}
throwOnInvalidObjectType(returnFiber, newChild);
}
return null;
}
/**
* Warns if there is a duplicate or missing key
*/
function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) {
// This algorithm can't optimize by searching from both ends since we
// don't have backpointers on fibers. I'm trying to see how far we can get
// with that model. If it ends up not being worth the tradeoffs, we can
// add it later.
// Even with a two ended optimization, we'd want to optimize for the case
// where there are few changes and brute force the comparison instead of
// going for the Map. It'd like to explore hitting that path first in
// forward-only mode and only go for the Map once we notice that we need
// lots of look ahead. This doesn't handle reversal as well as two ended
// search but that's unusual. Besides, for the two ended optimization to
// work on Iterables, we'd need to copy the whole set.
// In this first iteration, we'll just live with hitting the bad case
// (adding everything to a Map) in for every insert/move.
// If you change this code, also update reconcileChildrenIterator() which
// uses the same algorithm.
var resultingFirstChild = null;
var previousNewFiber = null;
var oldFiber = currentFirstChild;
var lastPlacedIndex = 0;
var newIdx = 0;
var nextOldFiber = null;
for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {
if (oldFiber.index > newIdx) {
nextOldFiber = oldFiber;
oldFiber = null;
} else {
nextOldFiber = oldFiber.sibling;
}
var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime);
if (newFiber === null) {
// TODO: This breaks on empty slots like null children. That's
// unfortunate because it triggers the slow path all the time. We need
// a better way to communicate whether this was a miss or null,
// boolean, undefined, etc.
if (oldFiber === null) {
oldFiber = nextOldFiber;
}
break;
}
if (shouldTrackSideEffects) {
if (oldFiber && newFiber.alternate === null) {
// We matched the slot, but we didn't reuse the existing fiber, so we
// need to delete the existing child.
deleteChild(returnFiber, oldFiber);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = newFiber;
} else {
// TODO: Defer siblings if we're not at the right index for this slot.
// I.e. if we had null values before, then we want to defer this
// for each null value. However, we also don't want to call updateSlot
// with the previous one.
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
if (newIdx === newChildren.length) {
// We've reached the end of the new children. We can delete the rest.
deleteRemainingChildren(returnFiber, oldFiber);
return resultingFirstChild;
}
if (oldFiber === null) {
// If we don't have any more existing children we can choose a fast path
// since the rest will all be insertions.
for (; newIdx < newChildren.length; newIdx++) {
var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime);
if (!_newFiber) {
continue;
}
lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = _newFiber;
} else {
previousNewFiber.sibling = _newFiber;
}
previousNewFiber = _newFiber;
}
return resultingFirstChild;
}
// Add all children to a key map for quick lookups.
var existingChildren = mapRemainingChildren(returnFiber, oldFiber);
// Keep scanning and use the map to restore deleted items as moves.
for (; newIdx < newChildren.length; newIdx++) {
var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime);
if (_newFiber2) {
if (shouldTrackSideEffects) {
if (_newFiber2.alternate !== null) {
// The new fiber is a work in progress, but if there exists a
// current, that means that we reused the fiber. We need to delete
// it from the child list so that we don't add it to the deletion
// list.
existingChildren.delete(_newFiber2.key === null ? newIdx : _newFiber2.key);
}
}
lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = _newFiber2;
} else {
previousNewFiber.sibling = _newFiber2;
}
previousNewFiber = _newFiber2;
}
}
if (shouldTrackSideEffects) {
// Any existing children that weren't consumed above were deleted. We need
// to add them to the deletion list.
existingChildren.forEach(function (child) {
return deleteChild(returnFiber, child);
});
}
return resultingFirstChild;
}
function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) {
// This is the same implementation as reconcileChildrenArray(),
// but using the iterator instead.
var iteratorFn = getIteratorFn(newChildrenIterable);
!(typeof iteratorFn === 'function') ? reactProdInvariant('150') : void 0;
var newChildren = iteratorFn.call(newChildrenIterable);
!(newChildren != null) ? reactProdInvariant('151') : void 0;
var resultingFirstChild = null;
var previousNewFiber = null;
var oldFiber = currentFirstChild;
var lastPlacedIndex = 0;
var newIdx = 0;
var nextOldFiber = null;
var step = newChildren.next();
for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) {
if (oldFiber.index > newIdx) {
nextOldFiber = oldFiber;
oldFiber = null;
} else {
nextOldFiber = oldFiber.sibling;
}
var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime);
if (newFiber === null) {
// TODO: This breaks on empty slots like null children. That's
// unfortunate because it triggers the slow path all the time. We need
// a better way to communicate whether this was a miss or null,
// boolean, undefined, etc.
if (!oldFiber) {
oldFiber = nextOldFiber;
}
break;
}
if (shouldTrackSideEffects) {
if (oldFiber && newFiber.alternate === null) {
// We matched the slot, but we didn't reuse the existing fiber, so we
// need to delete the existing child.
deleteChild(returnFiber, oldFiber);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = newFiber;
} else {
// TODO: Defer siblings if we're not at the right index for this slot.
// I.e. if we had null values before, then we want to defer this
// for each null value. However, we also don't want to call updateSlot
// with the previous one.
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
if (step.done) {
// We've reached the end of the new children. We can delete the rest.
deleteRemainingChildren(returnFiber, oldFiber);
return resultingFirstChild;
}
if (oldFiber === null) {
// If we don't have any more existing children we can choose a fast path
// since the rest will all be insertions.
for (; !step.done; newIdx++, step = newChildren.next()) {
var _newFiber3 = createChild(returnFiber, step.value, expirationTime);
if (_newFiber3 === null) {
continue;
}
lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = _newFiber3;
} else {
previousNewFiber.sibling = _newFiber3;
}
previousNewFiber = _newFiber3;
}
return resultingFirstChild;
}
// Add all children to a key map for quick lookups.
var existingChildren = mapRemainingChildren(returnFiber, oldFiber);
// Keep scanning and use the map to restore deleted items as moves.
for (; !step.done; newIdx++, step = newChildren.next()) {
var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime);
if (_newFiber4 !== null) {
if (shouldTrackSideEffects) {
if (_newFiber4.alternate !== null) {
// The new fiber is a work in progress, but if there exists a
// current, that means that we reused the fiber. We need to delete
// it from the child list so that we don't add it to the deletion
// list.
existingChildren.delete(_newFiber4.key === null ? newIdx : _newFiber4.key);
}
}
lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = _newFiber4;
} else {
previousNewFiber.sibling = _newFiber4;
}
previousNewFiber = _newFiber4;
}
}
if (shouldTrackSideEffects) {
// Any existing children that weren't consumed above were deleted. We need
// to add them to the deletion list.
existingChildren.forEach(function (child) {
return deleteChild(returnFiber, child);
});
}
return resultingFirstChild;
}
function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) {
// There's no need to check for keys on text nodes since we don't have a
// way to define them.
if (currentFirstChild !== null && currentFirstChild.tag === HostText) {
// We already have an existing node so let's just update it and delete
// the rest.
deleteRemainingChildren(returnFiber, currentFirstChild.sibling);
var existing = useFiber(currentFirstChild, textContent, expirationTime);
existing.return = returnFiber;
return existing;
}
// The existing first child is not a text node so we need to create one
// and delete the existing ones.
deleteRemainingChildren(returnFiber, currentFirstChild);
var created = createFiberFromText(textContent, returnFiber.mode, expirationTime);
created.return = returnFiber;
return created;
}
function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) {
var key = element.key;
var child = currentFirstChild;
while (child !== null) {
// TODO: If key === null and child.key === null, then this only applies to
// the first item in the list.
if (child.key === key) {
if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.elementType === element.type) {
deleteRemainingChildren(returnFiber, child.sibling);
var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime);
existing.ref = coerceRef(returnFiber, child, element);
existing.return = returnFiber;
return existing;
} else {
deleteRemainingChildren(returnFiber, child);
break;
}
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
if (element.type === REACT_FRAGMENT_TYPE) {
var created = createFiberFromFragment(element.props.children, returnFiber.mode, expirationTime, element.key);
created.return = returnFiber;
return created;
} else {
var _created4 = createFiberFromElement(element, returnFiber.mode, expirationTime);
_created4.ref = coerceRef(returnFiber, currentFirstChild, element);
_created4.return = returnFiber;
return _created4;
}
}
function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) {
var key = portal.key;
var child = currentFirstChild;
while (child !== null) {
// TODO: If key === null and child.key === null, then this only applies to
// the first item in the list.
if (child.key === key) {
if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) {
deleteRemainingChildren(returnFiber, child.sibling);
var existing = useFiber(child, portal.children || [], expirationTime);
existing.return = returnFiber;
return existing;
} else {
deleteRemainingChildren(returnFiber, child);
break;
}
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime);
created.return = returnFiber;
return created;
}
// This API will tag the children with the side-effect of the reconciliation
// itself. They will be added to the side-effect list as we pass through the
// children and the parent.
function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) {
// This function is not recursive.
// If the top level item is an array, we treat it as a set of children,
// not as a fragment. Nested arrays on the other hand will be treated as
// fragment nodes. Recursion happens at the normal flow.
// Handle top level unkeyed fragments as if they were arrays.
// This leads to an ambiguity between <>{[...]}</> and <>...</>.
// We treat the ambiguous cases above the same.
var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null;
if (isUnkeyedTopLevelFragment) {
newChild = newChild.props.children;
}
// Handle object types
var isObject = typeof newChild === 'object' && newChild !== null;
if (isObject) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime));
case REACT_PORTAL_TYPE:
return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime));
}
}
if (typeof newChild === 'string' || typeof newChild === 'number') {
return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime));
}
if (isArray(newChild)) {
return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime);
}
if (getIteratorFn(newChild)) {
return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime);
}
if (isObject) {
throwOnInvalidObjectType(returnFiber, newChild);
}
if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) {
// If the new child is undefined, and the return fiber is a composite
// component, throw an error. If Fiber return types are disabled,
// we already threw above.
switch (returnFiber.tag) {
case ClassComponent:
{
}
// Intentionally fall through to the next case, which handles both
// functions and classes
// eslint-disable-next-lined no-fallthrough
case FunctionComponent:
{
var Component = returnFiber.type;
reactProdInvariant('152', Component.displayName || Component.name || 'Component');
}
}
}
// Remaining cases are all treated as empty.
return deleteRemainingChildren(returnFiber, currentFirstChild);
}
return reconcileChildFibers;
}
var reconcileChildFibers = ChildReconciler(true);
var mountChildFibers = ChildReconciler(false);
function cloneChildFibers(current$$1, workInProgress) {
!(current$$1 === null || workInProgress.child === current$$1.child) ? reactProdInvariant('153') : void 0;
if (workInProgress.child === null) {
return;
}
var currentChild = workInProgress.child;
var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime);
workInProgress.child = newChild;
newChild.return = workInProgress;
while (currentChild.sibling !== null) {
currentChild = currentChild.sibling;
newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime);
newChild.return = workInProgress;
}
newChild.sibling = null;
}
var NO_CONTEXT = {};
var contextStackCursor$1 = createCursor(NO_CONTEXT);
var contextFiberStackCursor = createCursor(NO_CONTEXT);
var rootInstanceStackCursor = createCursor(NO_CONTEXT);
function requiredContext(c) {
!(c !== NO_CONTEXT) ? reactProdInvariant('174') : void 0;
return c;
}
function getRootHostContainer() {
var rootInstance = requiredContext(rootInstanceStackCursor.current);
return rootInstance;
}
function pushHostContainer(fiber, nextRootInstance) {
// Push current root instance onto the stack;
// This allows us to reset root when portals are popped.
push(rootInstanceStackCursor, nextRootInstance, fiber);
// Track the context and the Fiber that provided it.
// This enables us to pop only Fibers that provide unique contexts.
push(contextFiberStackCursor, fiber, fiber);
// Finally, we need to push the host context to the stack.
// However, we can't just call getRootHostContext() and push it because
// we'd have a different number of entries on the stack depending on
// whether getRootHostContext() throws somewhere in renderer code or not.
// So we push an empty value first. This lets us safely unwind on errors.
push(contextStackCursor$1, NO_CONTEXT, fiber);
var nextRootContext = getRootHostContext(nextRootInstance);
// Now that we know this function doesn't throw, replace it.
pop(contextStackCursor$1, fiber);
push(contextStackCursor$1, nextRootContext, fiber);
}
function popHostContainer(fiber) {
pop(contextStackCursor$1, fiber);
pop(contextFiberStackCursor, fiber);
pop(rootInstanceStackCursor, fiber);
}
function getHostContext() {
var context = requiredContext(contextStackCursor$1.current);
return context;
}
function pushHostContext(fiber) {
var rootInstance = requiredContext(rootInstanceStackCursor.current);
var context = requiredContext(contextStackCursor$1.current);
var nextContext = getChildHostContext(context, fiber.type, rootInstance);
// Don't push this Fiber's context unless it's unique.
if (context === nextContext) {
return;
}
// Track the context and the Fiber that provided it.
// This enables us to pop only Fibers that provide unique contexts.
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor$1, nextContext, fiber);
}
function popHostContext(fiber) {
// Do not pop unless this Fiber provided the current context.
// pushHostContext() only pushes Fibers that provide unique contexts.
if (contextFiberStackCursor.current !== fiber) {
return;
}
pop(contextStackCursor$1, fiber);
pop(contextFiberStackCursor, fiber);
}
var NoEffect$1 = /* */0;
var UnmountSnapshot = /* */2;
var UnmountMutation = /* */4;
var MountMutation = /* */8;
var UnmountLayout = /* */16;
var MountLayout = /* */32;
var MountPassive = /* */64;
var UnmountPassive = /* */128;
var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher;
// These are set right before calling the component.
var renderExpirationTime = NoWork;
// The work-in-progress fiber. I've named it differently to distinguish it from
// the work-in-progress hook.
var currentlyRenderingFiber$1 = null;
// Hooks are stored as a linked list on the fiber's memoizedState field. The
// current hook list is the list that belongs to the current fiber. The
// work-in-progress hook list is a new list that will be added to the
// work-in-progress fiber.
var currentHook = null;
var nextCurrentHook = null;
var firstWorkInProgressHook = null;
var workInProgressHook = null;
var nextWorkInProgressHook = null;
var remainingExpirationTime = NoWork;
var componentUpdateQueue = null;
var sideEffectTag = 0;
// Updates scheduled during render will trigger an immediate re-render at the
// end of the current pass. We can't store these updates on the normal queue,
// because if the work is aborted, they should be discarded. Because this is
// a relatively rare case, we also don't want to add an additional field to
// either the hook or queue object types. So we store them in a lazily create
// map of queue -> render-phase updates, which are discarded once the component
// completes without re-rendering.
// Whether an update was scheduled during the currently executing render pass.
var didScheduleRenderPhaseUpdate = false;
// Lazily created map of render-phase updates
var renderPhaseUpdates = null;
// Counter to prevent infinite loops.
var numberOfReRenders = 0;
var RE_RENDER_LIMIT = 25;
function throwInvalidHookError() {
reactProdInvariant('321');
}
function areHookInputsEqual(nextDeps, prevDeps) {
if (prevDeps === null) {
return false;
}
for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
if (is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
}
function renderWithHooks(current, workInProgress, Component, props, refOrContext, nextRenderExpirationTime) {
renderExpirationTime = nextRenderExpirationTime;
currentlyRenderingFiber$1 = workInProgress;
nextCurrentHook = current !== null ? current.memoizedState : null;
{
ReactCurrentDispatcher$1.current = nextCurrentHook === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate;
}
var children = Component(props, refOrContext);
if (didScheduleRenderPhaseUpdate) {
do {
didScheduleRenderPhaseUpdate = false;
numberOfReRenders += 1;
// Start over from the beginning of the list
nextCurrentHook = current !== null ? current.memoizedState : null;
nextWorkInProgressHook = firstWorkInProgressHook;
currentHook = null;
workInProgressHook = null;
componentUpdateQueue = null;
ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate;
children = Component(props, refOrContext);
} while (didScheduleRenderPhaseUpdate);
renderPhaseUpdates = null;
numberOfReRenders = 0;
}
// We can assume the previous dispatcher is always this one, since we set it
// at the beginning of the render phase and there's no re-entrancy.
ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
var renderedWork = currentlyRenderingFiber$1;
renderedWork.memoizedState = firstWorkInProgressHook;
renderedWork.expirationTime = remainingExpirationTime;
renderedWork.updateQueue = componentUpdateQueue;
renderedWork.effectTag |= sideEffectTag;
var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;
renderExpirationTime = NoWork;
currentlyRenderingFiber$1 = null;
currentHook = null;
nextCurrentHook = null;
firstWorkInProgressHook = null;
workInProgressHook = null;
nextWorkInProgressHook = null;
remainingExpirationTime = NoWork;
componentUpdateQueue = null;
sideEffectTag = 0;
// These were reset above
// didScheduleRenderPhaseUpdate = false;
// renderPhaseUpdates = null;
// numberOfReRenders = 0;
!!didRenderTooFewHooks ? reactProdInvariant('300') : void 0;
return children;
}
function bailoutHooks(current, workInProgress, expirationTime) {
workInProgress.updateQueue = current.updateQueue;
workInProgress.effectTag &= ~(Passive | Update);
if (current.expirationTime <= expirationTime) {
current.expirationTime = NoWork;
}
}
function resetHooks() {
// We can assume the previous dispatcher is always this one, since we set it
// at the beginning of the render phase and there's no re-entrancy.
ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;
// This is used to reset the state of this module when a component throws.
// It's also called inside mountIndeterminateComponent if we determine the
// component is a module-style component.
renderExpirationTime = NoWork;
currentlyRenderingFiber$1 = null;
currentHook = null;
nextCurrentHook = null;
firstWorkInProgressHook = null;
workInProgressHook = null;
nextWorkInProgressHook = null;
remainingExpirationTime = NoWork;
componentUpdateQueue = null;
sideEffectTag = 0;
didScheduleRenderPhaseUpdate = false;
renderPhaseUpdates = null;
numberOfReRenders = 0;
}
function mountWorkInProgressHook() {
var hook = {
memoizedState: null,
baseState: null,
queue: null,
baseUpdate: null,
next: null
};
if (workInProgressHook === null) {
// This is the first hook in the list
firstWorkInProgressHook = workInProgressHook = hook;
} else {
// Append to the end of the list
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
function updateWorkInProgressHook() {
// This function is used both for updates and for re-renders triggered by a
// render phase update. It assumes there is either a current hook we can
// clone, or a work-in-progress hook from a previous render pass that we can
// use as a base. When we reach the end of the base list, we must switch to
// the dispatcher used for mounts.
if (nextWorkInProgressHook !== null) {
// There's already a work-in-progress. Reuse it.
workInProgressHook = nextWorkInProgressHook;
nextWorkInProgressHook = workInProgressHook.next;
currentHook = nextCurrentHook;
nextCurrentHook = currentHook !== null ? currentHook.next : null;
} else {
// Clone from the current hook.
!(nextCurrentHook !== null) ? reactProdInvariant('310') : void 0;
currentHook = nextCurrentHook;
var newHook = {
memoizedState: currentHook.memoizedState,
baseState: currentHook.baseState,
queue: currentHook.queue,
baseUpdate: currentHook.baseUpdate,
next: null
};
if (workInProgressHook === null) {
// This is the first hook in the list.
workInProgressHook = firstWorkInProgressHook = newHook;
} else {
// Append to the end of the list.
workInProgressHook = workInProgressHook.next = newHook;
}
nextCurrentHook = currentHook.next;
}
return workInProgressHook;
}
function createFunctionComponentUpdateQueue() {
return {
lastEffect: null
};
}
function basicStateReducer(state, action) {
return typeof action === 'function' ? action(state) : action;
}
function mountReducer(reducer, initialArg, init) {
var hook = mountWorkInProgressHook();
var initialState = void 0;
if (init !== undefined) {
initialState = init(initialArg);
} else {
initialState = initialArg;
}
hook.memoizedState = hook.baseState = initialState;
var queue = hook.queue = {
last: null,
dispatch: null,
lastRenderedReducer: reducer,
lastRenderedState: initialState
};
var dispatch = queue.dispatch = dispatchAction.bind(null,
// Flow doesn't know this is non-null, but we do.
currentlyRenderingFiber$1, queue);
return [hook.memoizedState, dispatch];
}
function updateReducer(reducer, initialArg, init) {
var hook = updateWorkInProgressHook();
var queue = hook.queue;
!(queue !== null) ? reactProdInvariant('311') : void 0;
queue.lastRenderedReducer = reducer;
if (numberOfReRenders > 0) {
// This is a re-render. Apply the new render phase updates to the previous
var _dispatch = queue.dispatch;
if (renderPhaseUpdates !== null) {
// Render phase updates are stored in a map of queue -> linked list
var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
if (firstRenderPhaseUpdate !== undefined) {
renderPhaseUpdates.delete(queue);
var newState = hook.memoizedState;
var update = firstRenderPhaseUpdate;
do {
// Process this render phase update. We don't have to check the
// priority because it will always be the same as the current
// render's.
var _action = update.action;
newState = reducer(newState, _action);
update = update.next;
} while (update !== null);
// Mark that the fiber performed work, but only if the new state is
// different from the current state.
if (!is(newState, hook.memoizedState)) {
markWorkInProgressReceivedUpdate();
}
hook.memoizedState = newState;
// Don't persist the state accumlated from the render phase updates to
// the base state unless the queue is empty.
// TODO: Not sure if this is the desired semantics, but it's what we
// do for gDSFP. I can't remember why.
if (hook.baseUpdate === queue.last) {
hook.baseState = newState;
}
queue.lastRenderedState = newState;
return [newState, _dispatch];
}
}
return [hook.memoizedState, _dispatch];
}
// The last update in the entire queue
var last = queue.last;
// The last update that is part of the base state.
var baseUpdate = hook.baseUpdate;
var baseState = hook.baseState;
// Find the first unprocessed update.
var first = void 0;
if (baseUpdate !== null) {
if (last !== null) {
// For the first update, the queue is a circular linked list where
// `queue.last.next = queue.first`. Once the first update commits, and
// the `baseUpdate` is no longer empty, we can unravel the list.
last.next = null;
}
first = baseUpdate.next;
} else {
first = last !== null ? last.next : null;
}
if (first !== null) {
var _newState = baseState;
var newBaseState = null;
var newBaseUpdate = null;
var prevUpdate = baseUpdate;
var _update = first;
var didSkip = false;
do {
var updateExpirationTime = _update.expirationTime;
if (updateExpirationTime < renderExpirationTime) {
// Priority is insufficient. Skip this update. If this is the first
// skipped update, the previous update/state is the new base
// update/state.
if (!didSkip) {
didSkip = true;
newBaseUpdate = prevUpdate;
newBaseState = _newState;
}
// Update the remaining priority in the queue.
if (updateExpirationTime > remainingExpirationTime) {
remainingExpirationTime = updateExpirationTime;
}
} else {
// Process this update.
if (_update.eagerReducer === reducer) {
// If this update was processed eagerly, and its reducer matches the
// current reducer, we can use the eagerly computed state.
_newState = _update.eagerState;
} else {
var _action2 = _update.action;
_newState = reducer(_newState, _action2);
}
}
prevUpdate = _update;
_update = _update.next;
} while (_update !== null && _update !== first);
if (!didSkip) {
newBaseUpdate = prevUpdate;
newBaseState = _newState;
}
// Mark that the fiber performed work, but only if the new state is
// different from the current state.
if (!is(_newState, hook.memoizedState)) {
markWorkInProgressReceivedUpdate();
}
hook.memoizedState = _newState;
hook.baseUpdate = newBaseUpdate;
hook.baseState = newBaseState;
queue.lastRenderedState = _newState;
}
var dispatch = queue.dispatch;
return [hook.memoizedState, dispatch];
}
function mountState(initialState) {
var hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
var queue = hook.queue = {
last: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState
};
var dispatch = queue.dispatch = dispatchAction.bind(null,
// Flow doesn't know this is non-null, but we do.
currentlyRenderingFiber$1, queue);
return [hook.memoizedState, dispatch];
}
function updateState(initialState) {
return updateReducer(basicStateReducer, initialState);
}
function pushEffect(tag, create, destroy, deps) {
var effect = {
tag: tag,
create: create,
destroy: destroy,
deps: deps,
// Circular
next: null
};
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
var _lastEffect = componentUpdateQueue.lastEffect;
if (_lastEffect === null) {
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
var firstEffect = _lastEffect.next;
_lastEffect.next = effect;
effect.next = firstEffect;
componentUpdateQueue.lastEffect = effect;
}
}
return effect;
}
function mountRef(initialValue) {
var hook = mountWorkInProgressHook();
var ref = { current: initialValue };
hook.memoizedState = ref;
return ref;
}
function updateRef(initialValue) {
var hook = updateWorkInProgressHook();
return hook.memoizedState;
}
function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
var hook = mountWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
sideEffectTag |= fiberEffectTag;
hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps);
}
function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var destroy = undefined;
if (currentHook !== null) {
var prevEffect = currentHook.memoizedState;
destroy = prevEffect.destroy;
if (nextDeps !== null) {
var prevDeps = prevEffect.deps;
if (areHookInputsEqual(nextDeps, prevDeps)) {
pushEffect(NoEffect$1, create, destroy, nextDeps);
return;
}
}
}
sideEffectTag |= fiberEffectTag;
hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps);
}
function mountEffect(create, deps) {
return mountEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps);
}
function updateEffect(create, deps) {
return updateEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps);
}
function mountLayoutEffect(create, deps) {
return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
}
function updateLayoutEffect(create, deps) {
return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps);
}
function imperativeHandleEffect(create, ref) {
if (typeof ref === 'function') {
var refCallback = ref;
var _inst = create();
refCallback(_inst);
return function () {
refCallback(null);
};
} else if (ref !== null && ref !== undefined) {
var refObject = ref;
var _inst2 = create();
refObject.current = _inst2;
return function () {
refObject.current = null;
};
}
}
function mountImperativeHandle(ref, create, deps) {
var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null;
return mountEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps);
}
function updateImperativeHandle(ref, create, deps) {
var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null;
return updateEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps);
}
function mountDebugValue(value, formatterFn) {
// This hook is normally a no-op.
// The react-debug-hooks package injects its own implementation
// so that e.g. DevTools can display custom hook values.
}
var updateDebugValue = mountDebugValue;
function mountCallback(callback, deps) {
var hook = mountWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
hook.memoizedState = [callback, nextDeps];
return callback;
}
function updateCallback(callback, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;
if (prevState !== null) {
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
hook.memoizedState = [callback, nextDeps];
return callback;
}
function mountMemo(nextCreate, deps) {
var hook = mountWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
function updateMemo(nextCreate, deps) {
var hook = updateWorkInProgressHook();
var nextDeps = deps === undefined ? null : deps;
var prevState = hook.memoizedState;
if (prevState !== null) {
// Assume these are defined. If they're not, areHookInputsEqual will warn.
if (nextDeps !== null) {
var prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
var nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
function dispatchAction(fiber, queue, action) {
!(numberOfReRenders < RE_RENDER_LIMIT) ? reactProdInvariant('301') : void 0;
var alternate = fiber.alternate;
if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) {
// This is a render phase update. Stash it in a lazily-created map of
// queue -> linked list of updates. After this render pass, we'll restart
// and apply the stashed updates on top of the work-in-progress hook.
didScheduleRenderPhaseUpdate = true;
var update = {
expirationTime: renderExpirationTime,
action: action,
eagerReducer: null,
eagerState: null,
next: null
};
if (renderPhaseUpdates === null) {
renderPhaseUpdates = new Map();
}
var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
if (firstRenderPhaseUpdate === undefined) {
renderPhaseUpdates.set(queue, update);
} else {
// Append the update to the end of the list.
var lastRenderPhaseUpdate = firstRenderPhaseUpdate;
while (lastRenderPhaseUpdate.next !== null) {
lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
}
lastRenderPhaseUpdate.next = update;
}
} else {
flushPassiveEffects();
var currentTime = requestCurrentTime();
var _expirationTime = computeExpirationForFiber(currentTime, fiber);
var _update2 = {
expirationTime: _expirationTime,
action: action,
eagerReducer: null,
eagerState: null,
next: null
};
// Append the update to the end of the list.
var _last = queue.last;
if (_last === null) {
// This is the first update. Create a circular list.
_update2.next = _update2;
} else {
var first = _last.next;
if (first !== null) {
// Still circular.
_update2.next = first;
}
_last.next = _update2;
}
queue.last = _update2;
if (fiber.expirationTime === NoWork && (alternate === null || alternate.expirationTime === NoWork)) {
// The queue is currently empty, which means we can eagerly compute the
// next state before entering the render phase. If the new state is the
// same as the current state, we may be able to bail out entirely.
var _lastRenderedReducer = queue.lastRenderedReducer;
if (_lastRenderedReducer !== null) {
try {
var currentState = queue.lastRenderedState;
var _eagerState = _lastRenderedReducer(currentState, action);
// Stash the eagerly computed state, and the reducer used to compute
// it, on the update object. If the reducer hasn't changed by the
// time we enter the render phase, then the eager state can be used
// without calling the reducer again.
_update2.eagerReducer = _lastRenderedReducer;
_update2.eagerState = _eagerState;
if (is(_eagerState, currentState)) {
// Fast path. We can bail out without scheduling React to re-render.
// It's still possible that we'll need to rebase this update later,
// if the component re-renders for a different reason and by that
// time the reducer has changed.
return;
}
} catch (error) {
// Suppress the error. It will throw again in the render phase.
} finally {
}
}
}
scheduleWork(fiber, _expirationTime);
}
}
var ContextOnlyDispatcher = {
readContext: readContext,
useCallback: throwInvalidHookError,
useContext: throwInvalidHookError,
useEffect: throwInvalidHookError,
useImperativeHandle: throwInvalidHookError,
useLayoutEffect: throwInvalidHookError,
useMemo: throwInvalidHookError,
useReducer: throwInvalidHookError,
useRef: throwInvalidHookError,
useState: throwInvalidHookError,
useDebugValue: throwInvalidHookError
};
var HooksDispatcherOnMount = {
readContext: readContext,
useCallback: mountCallback,
useContext: readContext,
useEffect: mountEffect,
useImperativeHandle: mountImperativeHandle,
useLayoutEffect: mountLayoutEffect,
useMemo: mountMemo,
useReducer: mountReducer,
useRef: mountRef,
useState: mountState,
useDebugValue: mountDebugValue
};
var HooksDispatcherOnUpdate = {
readContext: readContext,
useCallback: updateCallback,
useContext: readContext,
useEffect: updateEffect,
useImperativeHandle: updateImperativeHandle,
useLayoutEffect: updateLayoutEffect,
useMemo: updateMemo,
useReducer: updateReducer,
useRef: updateRef,
useState: updateState,
useDebugValue: updateDebugValue
};
var commitTime = 0;
var profilerStartTime = -1;
function getCommitTime() {
return commitTime;
}
function recordCommitTime() {
if (!enableProfilerTimer) {
return;
}
commitTime = unstable_now();
}
function startProfilerTimer(fiber) {
if (!enableProfilerTimer) {
return;
}
profilerStartTime = unstable_now();
if (fiber.actualStartTime < 0) {
fiber.actualStartTime = unstable_now();
}
}
function stopProfilerTimerIfRunning(fiber) {
if (!enableProfilerTimer) {
return;
}
profilerStartTime = -1;
}
function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {
if (!enableProfilerTimer) {
return;
}
if (profilerStartTime >= 0) {
var elapsedTime = unstable_now() - profilerStartTime;
fiber.actualDuration += elapsedTime;
if (overrideBaseTime) {
fiber.selfBaseDuration = elapsedTime;
}
profilerStartTime = -1;
}
}
// The deepest Fiber on the stack involved in a hydration context.
// This may have been an insertion or a hydration.
var hydrationParentFiber = null;
var nextHydratableInstance = null;
var isHydrating = false;
function enterHydrationState(fiber) {
if (!supportsHydration) {
return false;
}
var parentInstance = fiber.stateNode.containerInfo;
nextHydratableInstance = getFirstHydratableChild(parentInstance);
hydrationParentFiber = fiber;
isHydrating = true;
return true;
}
function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) {
if (!supportsHydration) {
return false;
}
var suspenseInstance = fiber.stateNode;
nextHydratableInstance = getNextHydratableSibling(suspenseInstance);
popToNextHostParent(fiber);
isHydrating = true;
return true;
}
function deleteHydratableInstance(returnFiber, instance) {
var childToDelete = createFiberFromHostInstanceForDeletion();
childToDelete.stateNode = instance;
childToDelete.return = returnFiber;
childToDelete.effectTag = Deletion;
// This might seem like it belongs on progressedFirstDeletion. However,
// these children are not part of the reconciliation list of children.
// Even if we abort and rereconcile the children, that will try to hydrate
// again and the nodes are still in the host tree so these will be
// recreated.
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = childToDelete;
returnFiber.lastEffect = childToDelete;
} else {
returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
}
}
function insertNonHydratedInstance(returnFiber, fiber) {
fiber.effectTag |= Placement;
}
function tryHydrate(fiber, nextInstance) {
switch (fiber.tag) {
case HostComponent:
{
var type = fiber.type;
var props = fiber.pendingProps;
var instance = canHydrateInstance(nextInstance, type, props);
if (instance !== null) {
fiber.stateNode = instance;
return true;
}
return false;
}
case HostText:
{
var text = fiber.pendingProps;
var textInstance = canHydrateTextInstance(nextInstance, text);
if (textInstance !== null) {
fiber.stateNode = textInstance;
return true;
}
return false;
}
case SuspenseComponent:
{
if (enableSuspenseServerRenderer) {
var suspenseInstance = canHydrateSuspenseInstance(nextInstance);
if (suspenseInstance !== null) {
// Downgrade the tag to a dehydrated component until we've hydrated it.
fiber.tag = DehydratedSuspenseComponent;
fiber.stateNode = suspenseInstance;
return true;
}
}
return false;
}
default:
return false;
}
}
function tryToClaimNextHydratableInstance(fiber) {
if (!isHydrating) {
return;
}
var nextInstance = nextHydratableInstance;
if (!nextInstance) {
// Nothing to hydrate. Make it an insertion.
insertNonHydratedInstance(hydrationParentFiber, fiber);
isHydrating = false;
hydrationParentFiber = fiber;
return;
}
var firstAttemptedInstance = nextInstance;
if (!tryHydrate(fiber, nextInstance)) {
// If we can't hydrate this instance let's try the next one.
// We use this as a heuristic. It's based on intuition and not data so it
// might be flawed or unnecessary.
nextInstance = getNextHydratableSibling(firstAttemptedInstance);
if (!nextInstance || !tryHydrate(fiber, nextInstance)) {
// Nothing to hydrate. Make it an insertion.
insertNonHydratedInstance(hydrationParentFiber, fiber);
isHydrating = false;
hydrationParentFiber = fiber;
return;
}
// We matched the next one, we'll now assume that the first one was
// superfluous and we'll delete it. Since we can't eagerly delete it
// we'll have to schedule a deletion. To do that, this node needs a dummy
// fiber associated with it.
deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance);
}
hydrationParentFiber = fiber;
nextHydratableInstance = getFirstHydratableChild(nextInstance);
}
function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) {
if (!supportsHydration) {
reactProdInvariant('175');
}
var instance = fiber.stateNode;
var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber);
// TODO: Type this specific to this type of component.
fiber.updateQueue = updatePayload;
// If the update payload indicates that there is a change or if there
// is a new ref we mark this as an update.
if (updatePayload !== null) {
return true;
}
return false;
}
function prepareToHydrateHostTextInstance(fiber) {
if (!supportsHydration) {
reactProdInvariant('176');
}
var textInstance = fiber.stateNode;
var textContent = fiber.memoizedProps;
var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber);
return shouldUpdate;
}
function skipPastDehydratedSuspenseInstance(fiber) {
if (!supportsHydration) {
reactProdInvariant('316');
}
var suspenseInstance = fiber.stateNode;
!suspenseInstance ? reactProdInvariant('317') : void 0;
nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance);
}
function popToNextHostParent(fiber) {
var parent = fiber.return;
while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot && parent.tag !== DehydratedSuspenseComponent) {
parent = parent.return;
}
hydrationParentFiber = parent;
}
function popHydrationState(fiber) {
if (!supportsHydration) {
return false;
}
if (fiber !== hydrationParentFiber) {
// We're deeper than the current hydration context, inside an inserted
// tree.
return false;
}
if (!isHydrating) {
// If we're not currently hydrating but we're in a hydration context, then
// we were an insertion and now need to pop up reenter hydration of our
// siblings.
popToNextHostParent(fiber);
isHydrating = true;
return false;
}
var type = fiber.type;
// If we have any remaining hydratable nodes, we need to delete them now.
// We only do this deeper than head and body since they tend to have random
// other nodes in them. We also ignore components with pure text content in
// side of them.
// TODO: Better heuristic.
if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) {
var nextInstance = nextHydratableInstance;
while (nextInstance) {
deleteHydratableInstance(fiber, nextInstance);
nextInstance = getNextHydratableSibling(nextInstance);
}
}
popToNextHostParent(fiber);
nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null;
return true;
}
function resetHydrationState() {
if (!supportsHydration) {
return;
}
hydrationParentFiber = null;
nextHydratableInstance = null;
isHydrating = false;
}
var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;
var didReceiveUpdate = false;
function reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime) {
if (current$$1 === null) {
// If this is a fresh new component that hasn't been rendered yet, we
// won't update its child set by applying minimal side-effects. Instead,
// we will add them all to the child before it gets rendered. That means
// we can optimize this reconciliation pass by not tracking side-effects.
workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
} else {
// If the current child is the same as the work in progress, it means that
// we haven't yet started any work on these children. Therefore, we use
// the clone algorithm to create a copy of all the current children.
// If we had any progressed work already, that is invalid at this point so
// let's throw it out.
workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, nextChildren, renderExpirationTime);
}
}
function forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime) {
// This function is fork of reconcileChildren. It's used in cases where we
// want to reconcile without matching against the existing set. This has the
// effect of all current children being unmounted; even if the type and key
// are the same, the old child is unmounted and a new child is created.
//
// To do this, we're going to go through the reconcile algorithm twice. In
// the first pass, we schedule a deletion for all the current children by
// passing null.
workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, null, renderExpirationTime);
// In the second pass, we mount the new children. The trick here is that we
// pass null in place of where we usually pass the current child set. This has
// the effect of remounting all children regardless of whether their their
// identity matches.
workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
}
function updateForwardRef(current$$1, workInProgress, Component, nextProps, renderExpirationTime) {
// TODO: current can be non-null here even if the component
// hasn't yet mounted. This happens after the first render suspends.
// We'll need to figure out if this is fine or can cause issues.
var render = Component.render;
var ref = workInProgress.ref;
// The rest is a fork of updateFunctionComponent
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
{
nextChildren = renderWithHooks(current$$1, workInProgress, render, nextProps, ref, renderExpirationTime);
}
if (current$$1 !== null && !didReceiveUpdate) {
bailoutHooks(current$$1, workInProgress, renderExpirationTime);
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
return workInProgress.child;
}
function updateMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) {
if (current$$1 === null) {
var type = Component.type;
if (isSimpleFunctionComponent(type) && Component.compare === null &&
// SimpleMemoComponent codepath doesn't resolve outer props either.
Component.defaultProps === undefined) {
// If this is a plain function component without default props,
// and with only the default shallow comparison, we upgrade it
// to a SimpleMemoComponent to allow fast path updates.
workInProgress.tag = SimpleMemoComponent;
workInProgress.type = type;
return updateSimpleMemoComponent(current$$1, workInProgress, type, nextProps, updateExpirationTime, renderExpirationTime);
}
var child = createFiberFromTypeAndProps(Component.type, null, nextProps, null, workInProgress.mode, renderExpirationTime);
child.ref = workInProgress.ref;
child.return = workInProgress;
workInProgress.child = child;
return child;
}
var currentChild = current$$1.child; // This is always exactly one child
if (updateExpirationTime < renderExpirationTime) {
// This will be the props with resolved defaultProps,
// unlike current.memoizedProps which will be the unresolved ones.
var prevProps = currentChild.memoizedProps;
// Default to shallow comparison
var compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current$$1.ref === workInProgress.ref) {
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
var newChild = createWorkInProgress(currentChild, nextProps, renderExpirationTime);
newChild.ref = workInProgress.ref;
newChild.return = workInProgress;
workInProgress.child = newChild;
return newChild;
}
function updateSimpleMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) {
// TODO: current can be non-null here even if the component
// hasn't yet mounted. This happens when the inner render suspends.
// We'll need to figure out if this is fine or can cause issues.
if (current$$1 !== null) {
var prevProps = current$$1.memoizedProps;
if (shallowEqual(prevProps, nextProps) && current$$1.ref === workInProgress.ref) {
didReceiveUpdate = false;
if (updateExpirationTime < renderExpirationTime) {
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
}
}
return updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime);
}
function updateFragment(current$$1, workInProgress, renderExpirationTime) {
var nextChildren = workInProgress.pendingProps;
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
return workInProgress.child;
}
function updateMode(current$$1, workInProgress, renderExpirationTime) {
var nextChildren = workInProgress.pendingProps.children;
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
return workInProgress.child;
}
function updateProfiler(current$$1, workInProgress, renderExpirationTime) {
if (enableProfilerTimer) {
workInProgress.effectTag |= Update;
}
var nextProps = workInProgress.pendingProps;
var nextChildren = nextProps.children;
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
return workInProgress.child;
}
function markRef(current$$1, workInProgress) {
var ref = workInProgress.ref;
if (current$$1 === null && ref !== null || current$$1 !== null && current$$1.ref !== ref) {
// Schedule a Ref effect
workInProgress.effectTag |= Ref;
}
}
function updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) {
var unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
var context = getMaskedContext(workInProgress, unmaskedContext);
var nextChildren = void 0;
prepareToReadContext(workInProgress, renderExpirationTime);
{
nextChildren = renderWithHooks(current$$1, workInProgress, Component, nextProps, context, renderExpirationTime);
}
if (current$$1 !== null && !didReceiveUpdate) {
bailoutHooks(current$$1, workInProgress, renderExpirationTime);
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
return workInProgress.child;
}
function updateClassComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) {
var hasContext = void 0;
if (isContextProvider(Component)) {
hasContext = true;
pushContextProvider(workInProgress);
} else {
hasContext = false;
}
prepareToReadContext(workInProgress, renderExpirationTime);
var instance = workInProgress.stateNode;
var shouldUpdate = void 0;
if (instance === null) {
if (current$$1 !== null) {
// An class component without an instance only mounts if it suspended
// inside a non- concurrent tree, in an inconsistent state. We want to
// tree it like a new mount, even though an empty version of it already
// committed. Disconnect the alternate pointers.
current$$1.alternate = null;
workInProgress.alternate = null;
// Since this is conceptually a new fiber, schedule a Placement effect
workInProgress.effectTag |= Placement;
}
// In the initial pass we might need to construct the instance.
constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime);
mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime);
shouldUpdate = true;
} else if (current$$1 === null) {
// In a resume, we'll already have an instance we can reuse.
shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderExpirationTime);
} else {
shouldUpdate = updateClassInstance(current$$1, workInProgress, Component, nextProps, renderExpirationTime);
}
var nextUnitOfWork = finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime);
return nextUnitOfWork;
}
function finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime) {
// Refs should update even if shouldComponentUpdate returns false
markRef(current$$1, workInProgress);
var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect;
if (!shouldUpdate && !didCaptureError) {
// Context providers should defer to sCU for rendering
if (hasContext) {
invalidateContextProvider(workInProgress, Component, false);
}
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
var instance = workInProgress.stateNode;
// Rerender
ReactCurrentOwner$3.current = workInProgress;
var nextChildren = void 0;
if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') {
// If we captured an error, but getDerivedStateFrom catch is not defined,
// unmount all the children. componentDidCatch will schedule an update to
// re-render a fallback. This is temporary until we migrate everyone to
// the new API.
// TODO: Warn in a future release.
nextChildren = null;
if (enableProfilerTimer) {
stopProfilerTimerIfRunning(workInProgress);
}
} else {
{
nextChildren = instance.render();
}
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
if (current$$1 !== null && didCaptureError) {
// If we're recovering from an error, reconcile without reusing any of
// the existing children. Conceptually, the normal children and the children
// that are shown on error are two different sets, so we shouldn't reuse
// normal children even if their identities match.
forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime);
} else {
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
}
// Memoize state using the values we just used to render.
// TODO: Restructure so we never read values from the instance.
workInProgress.memoizedState = instance.state;
// The context might have changed so we need to recalculate it.
if (hasContext) {
invalidateContextProvider(workInProgress, Component, true);
}
return workInProgress.child;
}
function pushHostRootContext(workInProgress) {
var root = workInProgress.stateNode;
if (root.pendingContext) {
pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context);
} else if (root.context) {
// Should always be set
pushTopLevelContextObject(workInProgress, root.context, false);
}
pushHostContainer(workInProgress, root.containerInfo);
}
function updateHostRoot(current$$1, workInProgress, renderExpirationTime) {
pushHostRootContext(workInProgress);
var updateQueue = workInProgress.updateQueue;
!(updateQueue !== null) ? reactProdInvariant('282') : void 0;
var nextProps = workInProgress.pendingProps;
var prevState = workInProgress.memoizedState;
var prevChildren = prevState !== null ? prevState.element : null;
processUpdateQueue(workInProgress, updateQueue, nextProps, null, renderExpirationTime);
var nextState = workInProgress.memoizedState;
// Caution: React DevTools currently depends on this property
// being called "element".
var nextChildren = nextState.element;
if (nextChildren === prevChildren) {
// If the state is the same as before, that's a bailout because we had
// no work that expires at this time.
resetHydrationState();
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
var root = workInProgress.stateNode;
if ((current$$1 === null || current$$1.child === null) && root.hydrate && enterHydrationState(workInProgress)) {
// If we don't have any current children this might be the first pass.
// We always try to hydrate. If this isn't a hydration pass there won't
// be any children to hydrate which is effectively the same thing as
// not hydrating.
// This is a bit of a hack. We track the host root as a placement to
// know that we're currently in a mounting state. That way isMounted
// works as expected. We must reset this before committing.
// TODO: Delete this when we delete isMounted and findDOMNode.
workInProgress.effectTag |= Placement;
// Ensure that children mount into this root without tracking
// side-effects. This ensures that we don't store Placement effects on
// nodes that will be hydrated.
workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
} else {
// Otherwise reset hydration state in case we aborted and resumed another
// root.
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
resetHydrationState();
}
return workInProgress.child;
}
function updateHostComponent(current$$1, workInProgress, renderExpirationTime) {
pushHostContext(workInProgress);
if (current$$1 === null) {
tryToClaimNextHydratableInstance(workInProgress);
}
var type = workInProgress.type;
var nextProps = workInProgress.pendingProps;
var prevProps = current$$1 !== null ? current$$1.memoizedProps : null;
var nextChildren = nextProps.children;
var isDirectTextChild = shouldSetTextContent(type, nextProps);
if (isDirectTextChild) {
// We special case a direct text child of a host node. This is a common
// case. We won't handle it as a reified child. We will instead handle
// this in the host environment that also have access to this prop. That
// avoids allocating another HostText fiber and traversing it.
nextChildren = null;
} else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {
// If we're switching from a direct text child to a normal child, or to
// empty, we need to schedule the text content to be reset.
workInProgress.effectTag |= ContentReset;
}
markRef(current$$1, workInProgress);
// Check the host config to see if the children are offscreen/hidden.
if (renderExpirationTime !== Never && workInProgress.mode & ConcurrentMode && shouldDeprioritizeSubtree(type, nextProps)) {
// Schedule this fiber to re-render at offscreen priority. Then bailout.
workInProgress.expirationTime = workInProgress.childExpirationTime = Never;
return null;
}
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
return workInProgress.child;
}
function updateHostText(current$$1, workInProgress) {
if (current$$1 === null) {
tryToClaimNextHydratableInstance(workInProgress);
}
// Nothing to do here. This is terminal. We'll do the completion step
// immediately after.
return null;
}
function mountLazyComponent(_current, workInProgress, elementType, updateExpirationTime, renderExpirationTime) {
if (_current !== null) {
// An lazy component only mounts if it suspended inside a non-
// concurrent tree, in an inconsistent state. We want to treat it like
// a new mount, even though an empty version of it already committed.
// Disconnect the alternate pointers.
_current.alternate = null;
workInProgress.alternate = null;
// Since this is conceptually a new fiber, schedule a Placement effect
workInProgress.effectTag |= Placement;
}
var props = workInProgress.pendingProps;
// We can't start a User Timing measurement with correct label yet.
// Cancel and resume right after we know the tag.
cancelWorkTimer(workInProgress);
var Component = readLazyComponentType(elementType);
// Store the unwrapped component in the type.
workInProgress.type = Component;
var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component);
startWorkTimer(workInProgress);
var resolvedProps = resolveDefaultProps(Component, props);
var child = void 0;
switch (resolvedTag) {
case FunctionComponent:
{
child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime);
break;
}
case ClassComponent:
{
child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime);
break;
}
case ForwardRef:
{
child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderExpirationTime);
break;
}
case MemoComponent:
{
child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too
updateExpirationTime, renderExpirationTime);
break;
}
default:
{
var hint = '';
reactProdInvariant('306', Component, hint);
}
}
return child;
}
function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderExpirationTime) {
if (_current !== null) {
// An incomplete component only mounts if it suspended inside a non-
// concurrent tree, in an inconsistent state. We want to treat it like
// a new mount, even though an empty version of it already committed.
// Disconnect the alternate pointers.
_current.alternate = null;
workInProgress.alternate = null;
// Since this is conceptually a new fiber, schedule a Placement effect
workInProgress.effectTag |= Placement;
}
// Promote the fiber to a class and try rendering again.
workInProgress.tag = ClassComponent;
// The rest of this function is a fork of `updateClassComponent`
// Push context providers early to prevent context stack mismatches.
// During mounting we don't know the child context yet as the instance doesn't exist.
// We will invalidate the child context in finishClassComponent() right after rendering.
var hasContext = void 0;
if (isContextProvider(Component)) {
hasContext = true;
pushContextProvider(workInProgress);
} else {
hasContext = false;
}
prepareToReadContext(workInProgress, renderExpirationTime);
constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime);
mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime);
return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime);
}
function mountIndeterminateComponent(_current, workInProgress, Component, renderExpirationTime) {
if (_current !== null) {
// An indeterminate component only mounts if it suspended inside a non-
// concurrent tree, in an inconsistent state. We want to treat it like
// a new mount, even though an empty version of it already committed.
// Disconnect the alternate pointers.
_current.alternate = null;
workInProgress.alternate = null;
// Since this is conceptually a new fiber, schedule a Placement effect
workInProgress.effectTag |= Placement;
}
var props = workInProgress.pendingProps;
var unmaskedContext = getUnmaskedContext(workInProgress, Component, false);
var context = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
var value = void 0;
{
value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {
// Proceed under the assumption that this is a class instance
workInProgress.tag = ClassComponent;
// Throw out any hooks that were used.
resetHooks();
// Push context providers early to prevent context stack mismatches.
// During mounting we don't know the child context yet as the instance doesn't exist.
// We will invalidate the child context in finishClassComponent() right after rendering.
var hasContext = false;
if (isContextProvider(Component)) {
hasContext = true;
pushContextProvider(workInProgress);
} else {
hasContext = false;
}
workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null;
var getDerivedStateFromProps = Component.getDerivedStateFromProps;
if (typeof getDerivedStateFromProps === 'function') {
applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props);
}
adoptClassInstance(workInProgress, value);
mountClassInstance(workInProgress, Component, props, renderExpirationTime);
return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime);
} else {
// Proceed under the assumption that this is a function component
workInProgress.tag = FunctionComponent;
reconcileChildren(null, workInProgress, value, renderExpirationTime);
return workInProgress.child;
}
}
function updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime) {
var mode = workInProgress.mode;
var nextProps = workInProgress.pendingProps;
// We should attempt to render the primary children unless this boundary
// already suspended during this render (`alreadyCaptured` is true).
var nextState = workInProgress.memoizedState;
var nextDidTimeout = void 0;
if ((workInProgress.effectTag & DidCapture) === NoEffect) {
// This is the first attempt.
nextState = null;
nextDidTimeout = false;
} else {
// Something in this boundary's subtree already suspended. Switch to
// rendering the fallback children.
nextState = {
timedOutAt: nextState !== null ? nextState.timedOutAt : NoWork
};
nextDidTimeout = true;
workInProgress.effectTag &= ~DidCapture;
}
// This next part is a bit confusing. If the children timeout, we switch to
// showing the fallback children in place of the "primary" children.
// However, we don't want to delete the primary children because then their
// state will be lost (both the React state and the host state, e.g.
// uncontrolled form inputs). Instead we keep them mounted and hide them.
// Both the fallback children AND the primary children are rendered at the
// same time. Once the primary children are un-suspended, we can delete
// the fallback children — don't need to preserve their state.
//
// The two sets of children are siblings in the host environment, but
// semantically, for purposes of reconciliation, they are two separate sets.
// So we store them using two fragment fibers.
//
// However, we want to avoid allocating extra fibers for every placeholder.
// They're only necessary when the children time out, because that's the
// only time when both sets are mounted.
//
// So, the extra fragment fibers are only used if the children time out.
// Otherwise, we render the primary children directly. This requires some
// custom reconciliation logic to preserve the state of the primary
// children. It's essentially a very basic form of re-parenting.
// `child` points to the child fiber. In the normal case, this is the first
// fiber of the primary children set. In the timed-out case, it's a
// a fragment fiber containing the primary children.
var child = void 0;
// `next` points to the next fiber React should render. In the normal case,
// it's the same as `child`: the first fiber of the primary children set.
// In the timed-out case, it's a fragment fiber containing the *fallback*
// children -- we skip over the primary children entirely.
var next = void 0;
if (current$$1 === null) {
if (enableSuspenseServerRenderer) {
// If we're currently hydrating, try to hydrate this boundary.
// But only if this has a fallback.
if (nextProps.fallback !== undefined) {
tryToClaimNextHydratableInstance(workInProgress);
// This could've changed the tag if this was a dehydrated suspense component.
if (workInProgress.tag === DehydratedSuspenseComponent) {
return updateDehydratedSuspenseComponent(null, workInProgress, renderExpirationTime);
}
}
}
// This is the initial mount. This branch is pretty simple because there's
// no previous state that needs to be preserved.
if (nextDidTimeout) {
// Mount separate fragments for primary and fallback children.
var nextFallbackChildren = nextProps.fallback;
var primaryChildFragment = createFiberFromFragment(null, mode, NoWork, null);
if ((workInProgress.mode & ConcurrentMode) === NoContext) {
// Outside of concurrent mode, we commit the effects from the
var progressedState = workInProgress.memoizedState;
var progressedPrimaryChild = progressedState !== null ? workInProgress.child.child : workInProgress.child;
primaryChildFragment.child = progressedPrimaryChild;
}
var fallbackChildFragment = createFiberFromFragment(nextFallbackChildren, mode, renderExpirationTime, null);
primaryChildFragment.sibling = fallbackChildFragment;
child = primaryChildFragment;
// Skip the primary children, and continue working on the
// fallback children.
next = fallbackChildFragment;
child.return = next.return = workInProgress;
} else {
// Mount the primary children without an intermediate fragment fiber.
var nextPrimaryChildren = nextProps.children;
child = next = mountChildFibers(workInProgress, null, nextPrimaryChildren, renderExpirationTime);
}
} else {
// This is an update. This branch is more complicated because we need to
// ensure the state of the primary children is preserved.
var prevState = current$$1.memoizedState;
var prevDidTimeout = prevState !== null;
if (prevDidTimeout) {
// The current tree already timed out. That means each child set is
var currentPrimaryChildFragment = current$$1.child;
var currentFallbackChildFragment = currentPrimaryChildFragment.sibling;
if (nextDidTimeout) {
// Still timed out. Reuse the current primary children by cloning
// its fragment. We're going to skip over these entirely.
var _nextFallbackChildren = nextProps.fallback;
var _primaryChildFragment = createWorkInProgress(currentPrimaryChildFragment, currentPrimaryChildFragment.pendingProps, NoWork);
if ((workInProgress.mode & ConcurrentMode) === NoContext) {
// Outside of concurrent mode, we commit the effects from the
var _progressedState = workInProgress.memoizedState;
var _progressedPrimaryChild = _progressedState !== null ? workInProgress.child.child : workInProgress.child;
if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) {
_primaryChildFragment.child = _progressedPrimaryChild;
}
}
// Because primaryChildFragment is a new fiber that we're inserting as the
// parent of a new tree, we need to set its treeBaseDuration.
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
// treeBaseDuration is the sum of all the child tree base durations.
var treeBaseDuration = 0;
var hiddenChild = _primaryChildFragment.child;
while (hiddenChild !== null) {
treeBaseDuration += hiddenChild.treeBaseDuration;
hiddenChild = hiddenChild.sibling;
}
_primaryChildFragment.treeBaseDuration = treeBaseDuration;
}
// Clone the fallback child fragment, too. These we'll continue
// working on.
var _fallbackChildFragment = _primaryChildFragment.sibling = createWorkInProgress(currentFallbackChildFragment, _nextFallbackChildren, currentFallbackChildFragment.expirationTime);
child = _primaryChildFragment;
_primaryChildFragment.childExpirationTime = NoWork;
// Skip the primary children, and continue working on the
// fallback children.
next = _fallbackChildFragment;
child.return = next.return = workInProgress;
} else {
// No longer suspended. Switch back to showing the primary children,
// and remove the intermediate fragment fiber.
var _nextPrimaryChildren = nextProps.children;
var currentPrimaryChild = currentPrimaryChildFragment.child;
var primaryChild = reconcileChildFibers(workInProgress, currentPrimaryChild, _nextPrimaryChildren, renderExpirationTime);
// If this render doesn't suspend, we need to delete the fallback
// children. Wait until the complete phase, after we've confirmed the
// fallback is no longer needed.
// TODO: Would it be better to store the fallback fragment on
// the stateNode?
// Continue rendering the children, like we normally do.
child = next = primaryChild;
}
} else {
// The current tree has not already timed out. That means the primary
// children are not wrapped in a fragment fiber.
var _currentPrimaryChild = current$$1.child;
if (nextDidTimeout) {
// Timed out. Wrap the children in a fragment fiber to keep them
// separate from the fallback children.
var _nextFallbackChildren2 = nextProps.fallback;
var _primaryChildFragment2 = createFiberFromFragment(
// It shouldn't matter what the pending props are because we aren't
// going to render this fragment.
null, mode, NoWork, null);
_primaryChildFragment2.child = _currentPrimaryChild;
// Even though we're creating a new fiber, there are no new children,
// because we're reusing an already mounted tree. So we don't need to
// schedule a placement.
// primaryChildFragment.effectTag |= Placement;
if ((workInProgress.mode & ConcurrentMode) === NoContext) {
// Outside of concurrent mode, we commit the effects from the
var _progressedState2 = workInProgress.memoizedState;
var _progressedPrimaryChild2 = _progressedState2 !== null ? workInProgress.child.child : workInProgress.child;
_primaryChildFragment2.child = _progressedPrimaryChild2;
}
// Because primaryChildFragment is a new fiber that we're inserting as the
// parent of a new tree, we need to set its treeBaseDuration.
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
// treeBaseDuration is the sum of all the child tree base durations.
var _treeBaseDuration = 0;
var _hiddenChild = _primaryChildFragment2.child;
while (_hiddenChild !== null) {
_treeBaseDuration += _hiddenChild.treeBaseDuration;
_hiddenChild = _hiddenChild.sibling;
}
_primaryChildFragment2.treeBaseDuration = _treeBaseDuration;
}
// Create a fragment from the fallback children, too.
var _fallbackChildFragment2 = _primaryChildFragment2.sibling = createFiberFromFragment(_nextFallbackChildren2, mode, renderExpirationTime, null);
_fallbackChildFragment2.effectTag |= Placement;
child = _primaryChildFragment2;
_primaryChildFragment2.childExpirationTime = NoWork;
// Skip the primary children, and continue working on the
// fallback children.
next = _fallbackChildFragment2;
child.return = next.return = workInProgress;
} else {
// Still haven't timed out. Continue rendering the children, like we
// normally do.
var _nextPrimaryChildren2 = nextProps.children;
next = child = reconcileChildFibers(workInProgress, _currentPrimaryChild, _nextPrimaryChildren2, renderExpirationTime);
}
}
workInProgress.stateNode = current$$1.stateNode;
}
workInProgress.memoizedState = nextState;
workInProgress.child = child;
return next;
}
function updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime) {
if (current$$1 === null) {
// During the first pass, we'll bail out and not drill into the children.
// Instead, we'll leave the content in place and try to hydrate it later.
workInProgress.expirationTime = Never;
return null;
}
// We use childExpirationTime to indicate that a child might depend on context, so if
// any context has changed, we need to treat is as if the input might have changed.
var hasContextChanged$$1 = current$$1.childExpirationTime >= renderExpirationTime;
if (didReceiveUpdate || hasContextChanged$$1) {
// This boundary has changed since the first render. This means that we are now unable to
// hydrate it. We might still be able to hydrate it using an earlier expiration time but
// during this render we can't. Instead, we're going to delete the whole subtree and
// instead inject a new real Suspense boundary to take its place, which may render content
// or fallback. The real Suspense boundary will suspend for a while so we have some time
// to ensure it can produce real content, but all state and pending events will be lost.
// Detach from the current dehydrated boundary.
current$$1.alternate = null;
workInProgress.alternate = null;
// Insert a deletion in the effect list.
var returnFiber = workInProgress.return;
!(returnFiber !== null) ? reactProdInvariant('315') : void 0;
var last = returnFiber.lastEffect;
if (last !== null) {
last.nextEffect = current$$1;
returnFiber.lastEffect = current$$1;
} else {
returnFiber.firstEffect = returnFiber.lastEffect = current$$1;
}
current$$1.nextEffect = null;
current$$1.effectTag = Deletion;
// Upgrade this work in progress to a real Suspense component.
workInProgress.tag = SuspenseComponent;
workInProgress.stateNode = null;
workInProgress.memoizedState = null;
// This is now an insertion.
workInProgress.effectTag |= Placement;
// Retry as a real Suspense component.
return updateSuspenseComponent(null, workInProgress, renderExpirationTime);
}
if ((workInProgress.effectTag & DidCapture) === NoEffect) {
// This is the first attempt.
reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress);
var nextProps = workInProgress.pendingProps;
var nextChildren = nextProps.children;
workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
return workInProgress.child;
} else {
// Something suspended. Leave the existing children in place.
// TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far?
workInProgress.child = null;
return null;
}
}
function updatePortalComponent(current$$1, workInProgress, renderExpirationTime) {
pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);
var nextChildren = workInProgress.pendingProps;
if (current$$1 === null) {
// Portals are special because we don't append the children during mount
// but at commit. Therefore we need to track insertions which the normal
// flow doesn't do during mount. This doesn't happen at the root because
// the root always starts with a "current" with a null child.
// TODO: Consider unifying this with how the root works.
workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
} else {
reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime);
}
return workInProgress.child;
}
function updateContextProvider(current$$1, workInProgress, renderExpirationTime) {
var providerType = workInProgress.type;
var context = providerType._context;
var newProps = workInProgress.pendingProps;
var oldProps = workInProgress.memoizedProps;
var newValue = newProps.value;
pushProvider(workInProgress, newValue);
if (oldProps !== null) {
var oldValue = oldProps.value;
var changedBits = calculateChangedBits(context, newValue, oldValue);
if (changedBits === 0) {
// No change. Bailout early if children are the same.
if (oldProps.children === newProps.children && !hasContextChanged()) {
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
} else {
// The context value changed. Search for matching consumers and schedule
// them to update.
propagateContextChange(workInProgress, context, changedBits, renderExpirationTime);
}
}
var newChildren = newProps.children;
reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime);
return workInProgress.child;
}
function updateContextConsumer(current$$1, workInProgress, renderExpirationTime) {
var context = workInProgress.type;
// The logic below for Context differs depending on PROD or DEV mode. In
// DEV mode, we create a separate object for Context.Consumer that acts
// like a proxy to Context. This proxy object adds unnecessary code in PROD
// so we use the old behaviour (Context.Consumer references Context) to
// reduce size and overhead. The separate object references context via
// a property called "_context", which also gives us the ability to check
// in DEV mode if this property exists or not and warn if it does not.
var newProps = workInProgress.pendingProps;
var render = newProps.children;
prepareToReadContext(workInProgress, renderExpirationTime);
var newValue = readContext(context, newProps.unstable_observedBits);
var newChildren = void 0;
{
newChildren = render(newValue);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime);
return workInProgress.child;
}
function markWorkInProgressReceivedUpdate() {
didReceiveUpdate = true;
}
function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) {
cancelWorkTimer(workInProgress);
if (current$$1 !== null) {
// Reuse previous context list
workInProgress.contextDependencies = current$$1.contextDependencies;
}
if (enableProfilerTimer) {
// Don't update "base" render times for bailouts.
stopProfilerTimerIfRunning(workInProgress);
}
// Check if the children have any pending work.
var childExpirationTime = workInProgress.childExpirationTime;
if (childExpirationTime < renderExpirationTime) {
// The children don't have any work either. We can skip them.
// TODO: Once we add back resuming, we should check if the children are
// a work-in-progress set. If so, we need to transfer their effects.
return null;
} else {
// This fiber doesn't have work, but its subtree does. Clone the child
// fibers and continue.
cloneChildFibers(current$$1, workInProgress);
return workInProgress.child;
}
}
function beginWork(current$$1, workInProgress, renderExpirationTime) {
var updateExpirationTime = workInProgress.expirationTime;
if (current$$1 !== null) {
var oldProps = current$$1.memoizedProps;
var newProps = workInProgress.pendingProps;
if (oldProps !== newProps || hasContextChanged()) {
// If props or context changed, mark the fiber as having performed work.
// This may be unset if the props are determined to be equal later (memo).
didReceiveUpdate = true;
} else if (updateExpirationTime < renderExpirationTime) {
didReceiveUpdate = false;
// This fiber does not have any pending work. Bailout without entering
// the begin phase. There's still some bookkeeping we that needs to be done
// in this optimized path, mostly pushing stuff onto the stack.
switch (workInProgress.tag) {
case HostRoot:
pushHostRootContext(workInProgress);
resetHydrationState();
break;
case HostComponent:
pushHostContext(workInProgress);
break;
case ClassComponent:
{
var Component = workInProgress.type;
if (isContextProvider(Component)) {
pushContextProvider(workInProgress);
}
break;
}
case HostPortal:
pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);
break;
case ContextProvider:
{
var newValue = workInProgress.memoizedProps.value;
pushProvider(workInProgress, newValue);
break;
}
case Profiler:
if (enableProfilerTimer) {
workInProgress.effectTag |= Update;
}
break;
case SuspenseComponent:
{
var state = workInProgress.memoizedState;
var didTimeout = state !== null;
if (didTimeout) {
// If this boundary is currently timed out, we need to decide
// whether to retry the primary children, or to skip over it and
// go straight to the fallback. Check the priority of the primary
var primaryChildFragment = workInProgress.child;
var primaryChildExpirationTime = primaryChildFragment.childExpirationTime;
if (primaryChildExpirationTime !== NoWork && primaryChildExpirationTime >= renderExpirationTime) {
// The primary children have pending work. Use the normal path
// to attempt to render the primary children again.
return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime);
} else {
// The primary children do not have pending work with sufficient
// priority. Bailout.
var child = bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
if (child !== null) {
// The fallback children have pending work. Skip over the
// primary children and work on the fallback.
return child.sibling;
} else {
return null;
}
}
}
break;
}
case DehydratedSuspenseComponent:
{
if (enableSuspenseServerRenderer) {
// We know that this component will suspend again because if it has
// been unsuspended it has committed as a regular Suspense component.
// If it needs to be retried, it should have work scheduled on it.
workInProgress.effectTag |= DidCapture;
break;
}
}
}
return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime);
}
} else {
didReceiveUpdate = false;
}
// Before entering the begin phase, clear the expiration time.
workInProgress.expirationTime = NoWork;
switch (workInProgress.tag) {
case IndeterminateComponent:
{
var elementType = workInProgress.elementType;
return mountIndeterminateComponent(current$$1, workInProgress, elementType, renderExpirationTime);
}
case LazyComponent:
{
var _elementType = workInProgress.elementType;
return mountLazyComponent(current$$1, workInProgress, _elementType, updateExpirationTime, renderExpirationTime);
}
case FunctionComponent:
{
var _Component = workInProgress.type;
var unresolvedProps = workInProgress.pendingProps;
var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps);
return updateFunctionComponent(current$$1, workInProgress, _Component, resolvedProps, renderExpirationTime);
}
case ClassComponent:
{
var _Component2 = workInProgress.type;
var _unresolvedProps = workInProgress.pendingProps;
var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps);
return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime);
}
case HostRoot:
return updateHostRoot(current$$1, workInProgress, renderExpirationTime);
case HostComponent:
return updateHostComponent(current$$1, workInProgress, renderExpirationTime);
case HostText:
return updateHostText(current$$1, workInProgress);
case SuspenseComponent:
return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime);
case HostPortal:
return updatePortalComponent(current$$1, workInProgress, renderExpirationTime);
case ForwardRef:
{
var type = workInProgress.type;
var _unresolvedProps2 = workInProgress.pendingProps;
var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
return updateForwardRef(current$$1, workInProgress, type, _resolvedProps2, renderExpirationTime);
}
case Fragment:
return updateFragment(current$$1, workInProgress, renderExpirationTime);
case Mode:
return updateMode(current$$1, workInProgress, renderExpirationTime);
case Profiler:
return updateProfiler(current$$1, workInProgress, renderExpirationTime);
case ContextProvider:
return updateContextProvider(current$$1, workInProgress, renderExpirationTime);
case ContextConsumer:
return updateContextConsumer(current$$1, workInProgress, renderExpirationTime);
case MemoComponent:
{
var _type2 = workInProgress.type;
var _unresolvedProps3 = workInProgress.pendingProps;
// Resolve outer props first, then resolve inner props.
var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3);
_resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3);
return updateMemoComponent(current$$1, workInProgress, _type2, _resolvedProps3, updateExpirationTime, renderExpirationTime);
}
case SimpleMemoComponent:
{
return updateSimpleMemoComponent(current$$1, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime);
}
case IncompleteClassComponent:
{
var _Component3 = workInProgress.type;
var _unresolvedProps4 = workInProgress.pendingProps;
var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4);
return mountIncompleteClassComponent(current$$1, workInProgress, _Component3, _resolvedProps4, renderExpirationTime);
}
case DehydratedSuspenseComponent:
{
if (enableSuspenseServerRenderer) {
return updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime);
}
break;
}
}
reactProdInvariant('156');
}
var valueCursor = createCursor(null);
var currentlyRenderingFiber = null;
var lastContextDependency = null;
var lastContextWithAllBitsObserved = null;
function resetContextDependences() {
// This is called right before React yields execution, to ensure `readContext`
// cannot be called outside the render phase.
currentlyRenderingFiber = null;
lastContextDependency = null;
lastContextWithAllBitsObserved = null;
}
function pushProvider(providerFiber, nextValue) {
var context = providerFiber.type._context;
if (isPrimaryRenderer) {
push(valueCursor, context._currentValue, providerFiber);
context._currentValue = nextValue;
} else {
push(valueCursor, context._currentValue2, providerFiber);
context._currentValue2 = nextValue;
}
}
function popProvider(providerFiber) {
var currentValue = valueCursor.current;
pop(valueCursor, providerFiber);
var context = providerFiber.type._context;
if (isPrimaryRenderer) {
context._currentValue = currentValue;
} else {
context._currentValue2 = currentValue;
}
}
function calculateChangedBits(context, newValue, oldValue) {
if (is(oldValue, newValue)) {
// No change
return 0;
} else {
var changedBits = typeof context._calculateChangedBits === 'function' ? context._calculateChangedBits(oldValue, newValue) : maxSigned31BitInt;
return changedBits | 0;
}
}
function scheduleWorkOnParentPath(parent, renderExpirationTime) {
// Update the child expiration time of all the ancestors, including
// the alternates.
var node = parent;
while (node !== null) {
var alternate = node.alternate;
if (node.childExpirationTime < renderExpirationTime) {
node.childExpirationTime = renderExpirationTime;
if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) {
alternate.childExpirationTime = renderExpirationTime;
}
} else if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) {
alternate.childExpirationTime = renderExpirationTime;
} else {
// Neither alternate was updated, which means the rest of the
// ancestor path already has sufficient priority.
break;
}
node = node.return;
}
}
function propagateContextChange(workInProgress, context, changedBits, renderExpirationTime) {
var fiber = workInProgress.child;
if (fiber !== null) {
// Set the return pointer of the child to the work-in-progress fiber.
fiber.return = workInProgress;
}
while (fiber !== null) {
var nextFiber = void 0;
// Visit this fiber.
var list = fiber.contextDependencies;
if (list !== null) {
nextFiber = fiber.child;
var dependency = list.first;
while (dependency !== null) {
// Check if the context matches.
if (dependency.context === context && (dependency.observedBits & changedBits) !== 0) {
// Match! Schedule an update on this fiber.
if (fiber.tag === ClassComponent) {
// Schedule a force update on the work-in-progress.
var update = createUpdate(renderExpirationTime);
update.tag = ForceUpdate;
// TODO: Because we don't have a work-in-progress, this will add the
// update to the current fiber, too, which means it will persist even if
// this render is thrown away. Since it's a race condition, not sure it's
// worth fixing.
enqueueUpdate(fiber, update);
}
if (fiber.expirationTime < renderExpirationTime) {
fiber.expirationTime = renderExpirationTime;
}
var alternate = fiber.alternate;
if (alternate !== null && alternate.expirationTime < renderExpirationTime) {
alternate.expirationTime = renderExpirationTime;
}
scheduleWorkOnParentPath(fiber.return, renderExpirationTime);
// Mark the expiration time on the list, too.
if (list.expirationTime < renderExpirationTime) {
list.expirationTime = renderExpirationTime;
}
// Since we already found a match, we can stop traversing the
// dependency list.
break;
}
dependency = dependency.next;
}
} else if (fiber.tag === ContextProvider) {
// Don't scan deeper if this is a matching provider
nextFiber = fiber.type === workInProgress.type ? null : fiber.child;
} else if (enableSuspenseServerRenderer && fiber.tag === DehydratedSuspenseComponent) {
// If a dehydrated suspense component is in this subtree, we don't know
// if it will have any context consumers in it. The best we can do is
// mark it as having updates on its children.
if (fiber.expirationTime < renderExpirationTime) {
fiber.expirationTime = renderExpirationTime;
}
var _alternate = fiber.alternate;
if (_alternate !== null && _alternate.expirationTime < renderExpirationTime) {
_alternate.expirationTime = renderExpirationTime;
}
// This is intentionally passing this fiber as the parent
// because we want to schedule this fiber as having work
// on its children. We'll use the childExpirationTime on
// this fiber to indicate that a context has changed.
scheduleWorkOnParentPath(fiber, renderExpirationTime);
nextFiber = fiber.sibling;
} else {
// Traverse down.
nextFiber = fiber.child;
}
if (nextFiber !== null) {
// Set the return pointer of the child to the work-in-progress fiber.
nextFiber.return = fiber;
} else {
// No child. Traverse to next sibling.
nextFiber = fiber;
while (nextFiber !== null) {
if (nextFiber === workInProgress) {
// We're back to the root of this subtree. Exit.
nextFiber = null;
break;
}
var sibling = nextFiber.sibling;
if (sibling !== null) {
// Set the return pointer of the sibling to the work-in-progress fiber.
sibling.return = nextFiber.return;
nextFiber = sibling;
break;
}
// No more siblings. Traverse up.
nextFiber = nextFiber.return;
}
}
fiber = nextFiber;
}
}
function prepareToReadContext(workInProgress, renderExpirationTime) {
currentlyRenderingFiber = workInProgress;
lastContextDependency = null;
lastContextWithAllBitsObserved = null;
var currentDependencies = workInProgress.contextDependencies;
if (currentDependencies !== null && currentDependencies.expirationTime >= renderExpirationTime) {
// Context list has a pending update. Mark that this fiber performed work.
markWorkInProgressReceivedUpdate();
}
// Reset the work-in-progress list
workInProgress.contextDependencies = null;
}
function readContext(context, observedBits) {
if (lastContextWithAllBitsObserved === context) {
// Nothing to do. We already observe everything in this context.
} else if (observedBits === false || observedBits === 0) {
// Do not observe any updates.
} else {
var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types.
if (typeof observedBits !== 'number' || observedBits === maxSigned31BitInt) {
// Observe all updates.
lastContextWithAllBitsObserved = context;
resolvedObservedBits = maxSigned31BitInt;
} else {
resolvedObservedBits = observedBits;
}
var contextItem = {
context: context,
observedBits: resolvedObservedBits,
next: null
};
if (lastContextDependency === null) {
!(currentlyRenderingFiber !== null) ? reactProdInvariant('308') : void 0;
// This is the first dependency for this component. Create a new list.
lastContextDependency = contextItem;
currentlyRenderingFiber.contextDependencies = {
first: contextItem,
expirationTime: NoWork
};
} else {
// Append a new context item.
lastContextDependency = lastContextDependency.next = contextItem;
}
}
return isPrimaryRenderer ? context._currentValue : context._currentValue2;
}
// UpdateQueue is a linked list of prioritized updates.
//
// Like fibers, update queues come in pairs: a current queue, which represents
// the visible state of the screen, and a work-in-progress queue, which can be
// mutated and processed asynchronously before it is committed — a form of
// double buffering. If a work-in-progress render is discarded before finishing,
// we create a new work-in-progress by cloning the current queue.
//
// Both queues share a persistent, singly-linked list structure. To schedule an
// update, we append it to the end of both queues. Each queue maintains a
// pointer to first update in the persistent list that hasn't been processed.
// The work-in-progress pointer always has a position equal to or greater than
// the current queue, since we always work on that one. The current queue's
// pointer is only updated during the commit phase, when we swap in the
// work-in-progress.
//
// For example:
//
// Current pointer: A - B - C - D - E - F
// Work-in-progress pointer: D - E - F
// ^
// The work-in-progress queue has
// processed more updates than current.
//
// The reason we append to both queues is because otherwise we might drop
// updates without ever processing them. For example, if we only add updates to
// the work-in-progress queue, some updates could be lost whenever a work-in
// -progress render restarts by cloning from current. Similarly, if we only add
// updates to the current queue, the updates will be lost whenever an already
// in-progress queue commits and swaps with the current queue. However, by
// adding to both queues, we guarantee that the update will be part of the next
// work-in-progress. (And because the work-in-progress queue becomes the
// current queue once it commits, there's no danger of applying the same
// update twice.)
//
// Prioritization
// --------------
//
// Updates are not sorted by priority, but by insertion; new updates are always
// appended to the end of the list.
//
// The priority is still important, though. When processing the update queue
// during the render phase, only the updates with sufficient priority are
// included in the result. If we skip an update because it has insufficient
// priority, it remains in the queue to be processed later, during a lower
// priority render. Crucially, all updates subsequent to a skipped update also
// remain in the queue *regardless of their priority*. That means high priority
// updates are sometimes processed twice, at two separate priorities. We also
// keep track of a base state, that represents the state before the first
// update in the queue is applied.
//
// For example:
//
// Given a base state of '', and the following queue of updates
//
// A1 - B2 - C1 - D2
//
// where the number indicates the priority, and the update is applied to the
// previous state by appending a letter, React will process these updates as
// two separate renders, one per distinct priority level:
//
// First render, at priority 1:
// Base state: ''
// Updates: [A1, C1]
// Result state: 'AC'
//
// Second render, at priority 2:
// Base state: 'A' <- The base state does not include C1,
// because B2 was skipped.
// Updates: [B2, C1, D2] <- C1 was rebased on top of B2
// Result state: 'ABCD'
//
// Because we process updates in insertion order, and rebase high priority
// updates when preceding updates are skipped, the final result is deterministic
// regardless of priority. Intermediate state may vary according to system
// resources, but the final state is always the same.
var UpdateState = 0;
var ReplaceState = 1;
var ForceUpdate = 2;
var CaptureUpdate = 3;
// Global state that is reset at the beginning of calling `processUpdateQueue`.
// It should only be read right after calling `processUpdateQueue`, via
// `checkHasForceUpdateAfterProcessing`.
var hasForceUpdate = false;
function createUpdateQueue(baseState) {
var queue = {
baseState: baseState,
firstUpdate: null,
lastUpdate: null,
firstCapturedUpdate: null,
lastCapturedUpdate: null,
firstEffect: null,
lastEffect: null,
firstCapturedEffect: null,
lastCapturedEffect: null
};
return queue;
}
function cloneUpdateQueue(currentQueue) {
var queue = {
baseState: currentQueue.baseState,
firstUpdate: currentQueue.firstUpdate,
lastUpdate: currentQueue.lastUpdate,
// TODO: With resuming, if we bail out and resuse the child tree, we should
// keep these effects.
firstCapturedUpdate: null,
lastCapturedUpdate: null,
firstEffect: null,
lastEffect: null,
firstCapturedEffect: null,
lastCapturedEffect: null
};
return queue;
}
function createUpdate(expirationTime) {
return {
expirationTime: expirationTime,
tag: UpdateState,
payload: null,
callback: null,
next: null,
nextEffect: null
};
}
function appendUpdateToQueue(queue, update) {
// Append the update to the end of the list.
if (queue.lastUpdate === null) {
// Queue is empty
queue.firstUpdate = queue.lastUpdate = update;
} else {
queue.lastUpdate.next = update;
queue.lastUpdate = update;
}
}
function enqueueUpdate(fiber, update) {
// Update queues are created lazily.
var alternate = fiber.alternate;
var queue1 = void 0;
var queue2 = void 0;
if (alternate === null) {
// There's only one fiber.
queue1 = fiber.updateQueue;
queue2 = null;
if (queue1 === null) {
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
}
} else {
// There are two owners.
queue1 = fiber.updateQueue;
queue2 = alternate.updateQueue;
if (queue1 === null) {
if (queue2 === null) {
// Neither fiber has an update queue. Create new ones.
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
queue2 = alternate.updateQueue = createUpdateQueue(alternate.memoizedState);
} else {
// Only one fiber has an update queue. Clone to create a new one.
queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
}
} else {
if (queue2 === null) {
// Only one fiber has an update queue. Clone to create a new one.
queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
} else {
// Both owners have an update queue.
}
}
}
if (queue2 === null || queue1 === queue2) {
// There's only a single queue.
appendUpdateToQueue(queue1, update);
} else {
// There are two queues. We need to append the update to both queues,
// while accounting for the persistent structure of the list — we don't
// want the same update to be added multiple times.
if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
// One of the queues is not empty. We must add the update to both queues.
appendUpdateToQueue(queue1, update);
appendUpdateToQueue(queue2, update);
} else {
// Both queues are non-empty. The last update is the same in both lists,
// because of structural sharing. So, only append to one of the lists.
appendUpdateToQueue(queue1, update);
// But we still need to update the `lastUpdate` pointer of queue2.
queue2.lastUpdate = update;
}
}
}
function enqueueCapturedUpdate(workInProgress, update) {
// Captured updates go into a separate list, and only on the work-in-
// progress queue.
var workInProgressQueue = workInProgress.updateQueue;
if (workInProgressQueue === null) {
workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(workInProgress.memoizedState);
} else {
// TODO: I put this here rather than createWorkInProgress so that we don't
// clone the queue unnecessarily. There's probably a better way to
// structure this.
workInProgressQueue = ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue);
}
// Append the update to the end of the list.
if (workInProgressQueue.lastCapturedUpdate === null) {
// This is the first render phase update
workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;
} else {
workInProgressQueue.lastCapturedUpdate.next = update;
workInProgressQueue.lastCapturedUpdate = update;
}
}
function ensureWorkInProgressQueueIsAClone(workInProgress, queue) {
var current = workInProgress.alternate;
if (current !== null) {
// If the work-in-progress queue is equal to the current queue,
// we need to clone it first.
if (queue === current.updateQueue) {
queue = workInProgress.updateQueue = cloneUpdateQueue(queue);
}
}
return queue;
}
function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) {
switch (update.tag) {
case ReplaceState:
{
var _payload = update.payload;
if (typeof _payload === 'function') {
// Updater function
var nextState = _payload.call(instance, prevState, nextProps);
return nextState;
}
// State object
return _payload;
}
case CaptureUpdate:
{
workInProgress.effectTag = workInProgress.effectTag & ~ShouldCapture | DidCapture;
}
// Intentional fallthrough
case UpdateState:
{
var _payload2 = update.payload;
var partialState = void 0;
if (typeof _payload2 === 'function') {
// Updater function
partialState = _payload2.call(instance, prevState, nextProps);
} else {
// Partial state object
partialState = _payload2;
}
if (partialState === null || partialState === undefined) {
// Null and undefined are treated as no-ops.
return prevState;
}
// Merge the partial state and the previous state.
return _assign({}, prevState, partialState);
}
case ForceUpdate:
{
hasForceUpdate = true;
return prevState;
}
}
return prevState;
}
function processUpdateQueue(workInProgress, queue, props, instance, renderExpirationTime) {
hasForceUpdate = false;
queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
var newBaseState = queue.baseState;
var newFirstUpdate = null;
var newExpirationTime = NoWork;
// Iterate through the list of updates to compute the result.
var update = queue.firstUpdate;
var resultState = newBaseState;
while (update !== null) {
var updateExpirationTime = update.expirationTime;
if (updateExpirationTime < renderExpirationTime) {
// This update does not have sufficient priority. Skip it.
if (newFirstUpdate === null) {
// This is the first skipped update. It will be the first update in
// the new list.
newFirstUpdate = update;
// Since this is the first update that was skipped, the current result
// is the new base state.
newBaseState = resultState;
}
// Since this update will remain in the list, update the remaining
// expiration time.
if (newExpirationTime < updateExpirationTime) {
newExpirationTime = updateExpirationTime;
}
} else {
// This update does have sufficient priority. Process it and compute
// a new result.
resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance);
var _callback = update.callback;
if (_callback !== null) {
workInProgress.effectTag |= Callback;
// Set this to null, in case it was mutated during an aborted render.
update.nextEffect = null;
if (queue.lastEffect === null) {
queue.firstEffect = queue.lastEffect = update;
} else {
queue.lastEffect.nextEffect = update;
queue.lastEffect = update;
}
}
}
// Continue to the next update.
update = update.next;
}
// Separately, iterate though the list of captured updates.
var newFirstCapturedUpdate = null;
update = queue.firstCapturedUpdate;
while (update !== null) {
var _updateExpirationTime = update.expirationTime;
if (_updateExpirationTime < renderExpirationTime) {
// This update does not have sufficient priority. Skip it.
if (newFirstCapturedUpdate === null) {
// This is the first skipped captured update. It will be the first
// update in the new list.
newFirstCapturedUpdate = update;
// If this is the first update that was skipped, the current result is
// the new base state.
if (newFirstUpdate === null) {
newBaseState = resultState;
}
}
// Since this update will remain in the list, update the remaining
// expiration time.
if (newExpirationTime < _updateExpirationTime) {
newExpirationTime = _updateExpirationTime;
}
} else {
// This update does have sufficient priority. Process it and compute
// a new result.
resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance);
var _callback2 = update.callback;
if (_callback2 !== null) {
workInProgress.effectTag |= Callback;
// Set this to null, in case it was mutated during an aborted render.
update.nextEffect = null;
if (queue.lastCapturedEffect === null) {
queue.firstCapturedEffect = queue.lastCapturedEffect = update;
} else {
queue.lastCapturedEffect.nextEffect = update;
queue.lastCapturedEffect = update;
}
}
}
update = update.next;
}
if (newFirstUpdate === null) {
queue.lastUpdate = null;
}
if (newFirstCapturedUpdate === null) {
queue.lastCapturedUpdate = null;
} else {
workInProgress.effectTag |= Callback;
}
if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
// We processed every update, without skipping. That means the new base
// state is the same as the result state.
newBaseState = resultState;
}
queue.baseState = newBaseState;
queue.firstUpdate = newFirstUpdate;
queue.firstCapturedUpdate = newFirstCapturedUpdate;
// Set the remaining expiration time to be whatever is remaining in the queue.
// This should be fine because the only two other things that contribute to
// expiration time are props and context. We're already in the middle of the
// begin phase by the time we start processing the queue, so we've already
// dealt with the props. Context in components that specify
// shouldComponentUpdate is tricky; but we'll have to account for
// that regardless.
workInProgress.expirationTime = newExpirationTime;
workInProgress.memoizedState = resultState;
}
function callCallback(callback, context) {
!(typeof callback === 'function') ? reactProdInvariant('191', callback) : void 0;
callback.call(context);
}
function resetHasForceUpdateBeforeProcessing() {
hasForceUpdate = false;
}
function checkHasForceUpdateAfterProcessing() {
return hasForceUpdate;
}
function commitUpdateQueue(finishedWork, finishedQueue, instance, renderExpirationTime) {
// If the finished render included captured updates, and there are still
// lower priority updates left over, we need to keep the captured updates
// in the queue so that they are rebased and not dropped once we process the
// queue again at the lower priority.
if (finishedQueue.firstCapturedUpdate !== null) {
// Join the captured update list to the end of the normal list.
if (finishedQueue.lastUpdate !== null) {
finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate;
finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate;
}
// Clear the list of captured updates.
finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null;
}
// Commit the effects
commitUpdateEffects(finishedQueue.firstEffect, instance);
finishedQueue.firstEffect = finishedQueue.lastEffect = null;
commitUpdateEffects(finishedQueue.firstCapturedEffect, instance);
finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null;
}
function commitUpdateEffects(effect, instance) {
while (effect !== null) {
var _callback3 = effect.callback;
if (_callback3 !== null) {
effect.callback = null;
callCallback(_callback3, instance);
}
effect = effect.nextEffect;
}
}
function createCapturedValue(value, source) {
// If the value is an error, call this function immediately after it is thrown
// so the stack is accurate.
return {
value: value,
source: source,
stack: getStackByFiberInDevAndProd(source)
};
}
function markUpdate(workInProgress) {
// Tag the fiber with an update effect. This turns a Placement into
// a PlacementAndUpdate.
workInProgress.effectTag |= Update;
}
function markRef$1(workInProgress) {
workInProgress.effectTag |= Ref;
}
var appendAllChildren = void 0;
var updateHostContainer = void 0;
var updateHostComponent$1 = void 0;
var updateHostText$1 = void 0;
if (supportsMutation) {
// Mutation mode
appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
var node = workInProgress.child;
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText) {
appendInitialChild(parent, node.stateNode);
} else if (node.tag === HostPortal) {
// If we have a portal child, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};
updateHostContainer = function (workInProgress) {
// Noop
};
updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) {
// If we have an alternate, that means this is an update and we need to
// schedule a side-effect to do the updates.
var oldProps = current.memoizedProps;
if (oldProps === newProps) {
// In mutation mode, this is sufficient for a bailout because
// we won't touch this node even if children changed.
return;
}
// If we get updated because one of our children updated, we don't
// have newProps so we'll have to reuse them.
// TODO: Split the update API as separate for the props vs. children.
// Even better would be if children weren't special cased at all tho.
var instance = workInProgress.stateNode;
var currentHostContext = getHostContext();
// TODO: Experiencing an error where oldProps is null. Suggests a host
// component is hitting the resume path. Figure out why. Possibly
// related to `hidden`.
var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext);
// TODO: Type this specific to this type of component.
workInProgress.updateQueue = updatePayload;
// If the update payload indicates that there is a change or if there
// is a new ref we mark this as an update. All the work is done in commitWork.
if (updatePayload) {
markUpdate(workInProgress);
}
};
updateHostText$1 = function (current, workInProgress, oldText, newText) {
// If the text differs, mark it as an update. All the work in done in commitWork.
if (oldText !== newText) {
markUpdate(workInProgress);
}
};
} else if (supportsPersistence) {
// Persistent host tree mode
appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
var node = workInProgress.child;
while (node !== null) {
// eslint-disable-next-line no-labels
branches: if (node.tag === HostComponent) {
var instance = node.stateNode;
if (needsVisibilityToggle) {
var props = node.memoizedProps;
var type = node.type;
if (isHidden) {
// This child is inside a timed out tree. Hide it.
instance = cloneHiddenInstance(instance, type, props, node);
} else {
// This child was previously inside a timed out tree. If it was not
// updated during this render, it may need to be unhidden. Clone
// again to be sure.
instance = cloneUnhiddenInstance(instance, type, props, node);
}
node.stateNode = instance;
}
appendInitialChild(parent, instance);
} else if (node.tag === HostText) {
var _instance = node.stateNode;
if (needsVisibilityToggle) {
var text = node.memoizedProps;
var rootContainerInstance = getRootHostContainer();
var currentHostContext = getHostContext();
if (isHidden) {
_instance = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress);
} else {
_instance = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress);
}
node.stateNode = _instance;
}
appendInitialChild(parent, _instance);
} else if (node.tag === HostPortal) {
// If we have a portal child, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (node.tag === SuspenseComponent) {
var current = node.alternate;
if (current !== null) {
var oldState = current.memoizedState;
var newState = node.memoizedState;
var oldIsHidden = oldState !== null;
var newIsHidden = newState !== null;
if (oldIsHidden !== newIsHidden) {
// The placeholder either just timed out or switched back to the normal
// children after having previously timed out. Toggle the visibility of
// the direct host children.
var primaryChildParent = newIsHidden ? node.child : node;
if (primaryChildParent !== null) {
appendAllChildren(parent, primaryChildParent, true, newIsHidden);
}
// eslint-disable-next-line no-labels
break branches;
}
}
if (node.child !== null) {
// Continue traversing like normal
node.child.return = node;
node = node.child;
continue;
}
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
// $FlowFixMe This is correct but Flow is confused by the labeled break.
node = node;
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};
// An unfortunate fork of appendAllChildren because we have two different parent types.
var appendAllChildrenToContainer = function (containerChildSet, workInProgress, needsVisibilityToggle, isHidden) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
var node = workInProgress.child;
while (node !== null) {
// eslint-disable-next-line no-labels
branches: if (node.tag === HostComponent) {
var instance = node.stateNode;
if (needsVisibilityToggle) {
var props = node.memoizedProps;
var type = node.type;
if (isHidden) {
// This child is inside a timed out tree. Hide it.
instance = cloneHiddenInstance(instance, type, props, node);
} else {
// This child was previously inside a timed out tree. If it was not
// updated during this render, it may need to be unhidden. Clone
// again to be sure.
instance = cloneUnhiddenInstance(instance, type, props, node);
}
node.stateNode = instance;
}
appendChildToContainerChildSet(containerChildSet, instance);
} else if (node.tag === HostText) {
var _instance2 = node.stateNode;
if (needsVisibilityToggle) {
var text = node.memoizedProps;
var rootContainerInstance = getRootHostContainer();
var currentHostContext = getHostContext();
if (isHidden) {
_instance2 = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress);
} else {
_instance2 = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress);
}
node.stateNode = _instance2;
}
appendChildToContainerChildSet(containerChildSet, _instance2);
} else if (node.tag === HostPortal) {
// If we have a portal child, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (node.tag === SuspenseComponent) {
var current = node.alternate;
if (current !== null) {
var oldState = current.memoizedState;
var newState = node.memoizedState;
var oldIsHidden = oldState !== null;
var newIsHidden = newState !== null;
if (oldIsHidden !== newIsHidden) {
// The placeholder either just timed out or switched back to the normal
// children after having previously timed out. Toggle the visibility of
// the direct host children.
var primaryChildParent = newIsHidden ? node.child : node;
if (primaryChildParent !== null) {
appendAllChildrenToContainer(containerChildSet, primaryChildParent, true, newIsHidden);
}
// eslint-disable-next-line no-labels
break branches;
}
}
if (node.child !== null) {
// Continue traversing like normal
node.child.return = node;
node = node.child;
continue;
}
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
// $FlowFixMe This is correct but Flow is confused by the labeled break.
node = node;
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};
updateHostContainer = function (workInProgress) {
var portalOrRoot = workInProgress.stateNode;
var childrenUnchanged = workInProgress.firstEffect === null;
if (childrenUnchanged) {
// No changes, just reuse the existing instance.
} else {
var container = portalOrRoot.containerInfo;
var newChildSet = createContainerChildSet(container);
// If children might have changed, we have to add them all to the set.
appendAllChildrenToContainer(newChildSet, workInProgress, false, false);
portalOrRoot.pendingChildren = newChildSet;
// Schedule an update on the container to swap out the container.
markUpdate(workInProgress);
finalizeContainerChildren(container, newChildSet);
}
};
updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) {
var currentInstance = current.stateNode;
var oldProps = current.memoizedProps;
// If there are no effects associated with this node, then none of our children had any updates.
// This guarantees that we can reuse all of them.
var childrenUnchanged = workInProgress.firstEffect === null;
if (childrenUnchanged && oldProps === newProps) {
// No changes, just reuse the existing instance.
// Note that this might release a previous clone.
workInProgress.stateNode = currentInstance;
return;
}
var recyclableInstance = workInProgress.stateNode;
var currentHostContext = getHostContext();
var updatePayload = null;
if (oldProps !== newProps) {
updatePayload = prepareUpdate(recyclableInstance, type, oldProps, newProps, rootContainerInstance, currentHostContext);
}
if (childrenUnchanged && updatePayload === null) {
// No changes, just reuse the existing instance.
// Note that this might release a previous clone.
workInProgress.stateNode = currentInstance;
return;
}
var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance);
if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance, currentHostContext)) {
markUpdate(workInProgress);
}
workInProgress.stateNode = newInstance;
if (childrenUnchanged) {
// If there are no other effects in this tree, we need to flag this node as having one.
// Even though we're not going to use it for anything.
// Otherwise parents won't know that there are new children to propagate upwards.
markUpdate(workInProgress);
} else {
// If children might have changed, we have to add them all to the set.
appendAllChildren(newInstance, workInProgress, false, false);
}
};
updateHostText$1 = function (current, workInProgress, oldText, newText) {
if (oldText !== newText) {
// If the text content differs, we'll create a new text instance for it.
var rootContainerInstance = getRootHostContainer();
var currentHostContext = getHostContext();
workInProgress.stateNode = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress);
// We'll have to mark it as having an effect, even though we won't use the effect for anything.
// This lets the parents know that at least one of their children has changed.
markUpdate(workInProgress);
}
};
} else {
// No host operations
updateHostContainer = function (workInProgress) {
// Noop
};
updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) {
// Noop
};
updateHostText$1 = function (current, workInProgress, oldText, newText) {
// Noop
};
}
function completeWork(current, workInProgress, renderExpirationTime) {
var newProps = workInProgress.pendingProps;
switch (workInProgress.tag) {
case IndeterminateComponent:
break;
case LazyComponent:
break;
case SimpleMemoComponent:
case FunctionComponent:
break;
case ClassComponent:
{
var Component = workInProgress.type;
if (isContextProvider(Component)) {
popContext(workInProgress);
}
break;
}
case HostRoot:
{
popHostContainer(workInProgress);
popTopLevelContextObject(workInProgress);
var fiberRoot = workInProgress.stateNode;
if (fiberRoot.pendingContext) {
fiberRoot.context = fiberRoot.pendingContext;
fiberRoot.pendingContext = null;
}
if (current === null || current.child === null) {
// If we hydrated, pop so that we can delete any remaining children
// that weren't hydrated.
popHydrationState(workInProgress);
// This resets the hacky state to fix isMounted before committing.
// TODO: Delete this when we delete isMounted and findDOMNode.
workInProgress.effectTag &= ~Placement;
}
updateHostContainer(workInProgress);
break;
}
case HostComponent:
{
popHostContext(workInProgress);
var rootContainerInstance = getRootHostContainer();
var type = workInProgress.type;
if (current !== null && workInProgress.stateNode != null) {
updateHostComponent$1(current, workInProgress, type, newProps, rootContainerInstance);
if (current.ref !== workInProgress.ref) {
markRef$1(workInProgress);
}
} else {
if (!newProps) {
!(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0;
// This can happen when we abort work.
break;
}
var currentHostContext = getHostContext();
// TODO: Move createInstance to beginWork and keep it on a context
// "stack" as the parent. Then append children as we go in beginWork
// or completeWork depending on we want to add then top->down or
// bottom->up. Top->down is faster in IE11.
var wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
// TODO: Move this and createInstance step into the beginPhase
// to consolidate.
if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, currentHostContext)) {
// If changes to the hydrated node needs to be applied at the
// commit-phase we mark this as such.
markUpdate(workInProgress);
}
} else {
var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress);
appendAllChildren(instance, workInProgress, false, false);
// Certain renderers require commit-time effects for initial mount.
// (eg DOM renderer supports auto-focus for certain elements).
// Make sure such renderers get scheduled for later work.
if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance, currentHostContext)) {
markUpdate(workInProgress);
}
workInProgress.stateNode = instance;
}
if (workInProgress.ref !== null) {
// If there is a ref on a host node we need to schedule a callback
markRef$1(workInProgress);
}
}
break;
}
case HostText:
{
var newText = newProps;
if (current && workInProgress.stateNode != null) {
var oldText = current.memoizedProps;
// If we have an alternate, that means this is an update and we need
// to schedule a side-effect to do the updates.
updateHostText$1(current, workInProgress, oldText, newText);
} else {
if (typeof newText !== 'string') {
!(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0;
// This can happen when we abort work.
}
var _rootContainerInstance = getRootHostContainer();
var _currentHostContext = getHostContext();
var _wasHydrated = popHydrationState(workInProgress);
if (_wasHydrated) {
if (prepareToHydrateHostTextInstance(workInProgress)) {
markUpdate(workInProgress);
}
} else {
workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext, workInProgress);
}
}
break;
}
case ForwardRef:
break;
case SuspenseComponent:
{
var nextState = workInProgress.memoizedState;
if ((workInProgress.effectTag & DidCapture) !== NoEffect) {
// Something suspended. Re-render with the fallback children.
workInProgress.expirationTime = renderExpirationTime;
// Do not reset the effect list.
return workInProgress;
}
var nextDidTimeout = nextState !== null;
var prevDidTimeout = current !== null && current.memoizedState !== null;
if (current !== null && !nextDidTimeout && prevDidTimeout) {
// We just switched from the fallback to the normal children. Delete
// the fallback.
// TODO: Would it be better to store the fallback fragment on
var currentFallbackChild = current.child.sibling;
if (currentFallbackChild !== null) {
// Deletions go at the beginning of the return fiber's effect list
var first = workInProgress.firstEffect;
if (first !== null) {
workInProgress.firstEffect = currentFallbackChild;
currentFallbackChild.nextEffect = first;
} else {
workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild;
currentFallbackChild.nextEffect = null;
}
currentFallbackChild.effectTag = Deletion;
}
}
if (nextDidTimeout || prevDidTimeout) {
// If the children are hidden, or if they were previous hidden, schedule
// an effect to toggle their visibility. This is also used to attach a
// retry listener to the promise.
workInProgress.effectTag |= Update;
}
break;
}
case Fragment:
break;
case Mode:
break;
case Profiler:
break;
case HostPortal:
popHostContainer(workInProgress);
updateHostContainer(workInProgress);
break;
case ContextProvider:
// Pop provider fiber
popProvider(workInProgress);
break;
case ContextConsumer:
break;
case MemoComponent:
break;
case IncompleteClassComponent:
{
// Same as class component case. I put it down here so that the tags are
// sequential to ensure this switch is compiled to a jump table.
var _Component = workInProgress.type;
if (isContextProvider(_Component)) {
popContext(workInProgress);
}
break;
}
case DehydratedSuspenseComponent:
{
if (enableSuspenseServerRenderer) {
if (current === null) {
var _wasHydrated2 = popHydrationState(workInProgress);
!_wasHydrated2 ? reactProdInvariant('318') : void 0;
skipPastDehydratedSuspenseInstance(workInProgress);
} else if ((workInProgress.effectTag & DidCapture) === NoEffect) {
// This boundary did not suspend so it's now hydrated.
// To handle any future suspense cases, we're going to now upgrade it
// to a Suspense component. We detach it from the existing current fiber.
current.alternate = null;
workInProgress.alternate = null;
workInProgress.tag = SuspenseComponent;
workInProgress.memoizedState = null;
workInProgress.stateNode = null;
}
}
break;
}
default:
reactProdInvariant('156');
}
return null;
}
function shouldCaptureSuspense(workInProgress) {
// In order to capture, the Suspense component must have a fallback prop.
if (workInProgress.memoizedProps.fallback === undefined) {
return false;
}
// If it was the primary children that just suspended, capture and render the
// fallback. Otherwise, don't capture and bubble to the next boundary.
var nextState = workInProgress.memoizedState;
return nextState === null;
}
// This module is forked in different environments.
// By default, return `true` to log errors to the console.
// Forks can return `false` if this isn't desirable.
function showErrorDialog(capturedError) {
return true;
}
function logCapturedError(capturedError) {
var logError = showErrorDialog(capturedError);
// Allow injected showErrorDialog() to prevent default console.error logging.
// This enables renderers like ReactNative to better manage redbox behavior.
if (logError === false) {
return;
}
var error = capturedError.error;
{
// In production, we print the error directly.
// This will include the message, the JS stack, and anything the browser wants to show.
// We pass the error object instead of custom message so that the browser displays the error natively.
console.error(error);
}
}
var PossiblyWeakSet$1 = typeof WeakSet === 'function' ? WeakSet : Set;
function logError(boundary, errorInfo) {
var source = errorInfo.source;
var stack = errorInfo.stack;
if (stack === null && source !== null) {
stack = getStackByFiberInDevAndProd(source);
}
var capturedError = {
componentName: source !== null ? getComponentName(source.type) : null,
componentStack: stack !== null ? stack : '',
error: errorInfo.value,
errorBoundary: null,
errorBoundaryName: null,
errorBoundaryFound: false,
willRetry: false
};
if (boundary !== null && boundary.tag === ClassComponent) {
capturedError.errorBoundary = boundary.stateNode;
capturedError.errorBoundaryName = getComponentName(boundary.type);
capturedError.errorBoundaryFound = true;
capturedError.willRetry = true;
}
try {
logCapturedError(capturedError);
} catch (e) {
// This method must not throw, or React internal state will get messed up.
// If console.error is overridden, or logCapturedError() shows a dialog that throws,
// we want to report this error outside of the normal stack as a last resort.
setTimeout(function () {
throw e;
});
}
}
var callComponentWillUnmountWithTimer = function (current$$1, instance) {
startPhaseTimer(current$$1, 'componentWillUnmount');
instance.props = current$$1.memoizedProps;
instance.state = current$$1.memoizedState;
instance.componentWillUnmount();
stopPhaseTimer();
};
// Capture errors so they don't interrupt unmounting.
function safelyCallComponentWillUnmount(current$$1, instance) {
{
try {
callComponentWillUnmountWithTimer(current$$1, instance);
} catch (unmountError) {
captureCommitPhaseError(current$$1, unmountError);
}
}
}
function safelyDetachRef(current$$1) {
var ref = current$$1.ref;
if (ref !== null) {
if (typeof ref === 'function') {
{
try {
ref(null);
} catch (refError) {
captureCommitPhaseError(current$$1, refError);
}
}
} else {
ref.current = null;
}
}
}
function safelyCallDestroy(current$$1, destroy) {
{
try {
destroy();
} catch (error) {
captureCommitPhaseError(current$$1, error);
}
}
}
function commitBeforeMutationLifeCycles(current$$1, finishedWork) {
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent:
{
commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork);
return;
}
case ClassComponent:
{
if (finishedWork.effectTag & Snapshot) {
if (current$$1 !== null) {
var prevProps = current$$1.memoizedProps;
var prevState = current$$1.memoizedState;
startPhaseTimer(finishedWork, 'getSnapshotBeforeUpdate');
var instance = finishedWork.stateNode;
// We could update instance props and state here,
// but instead we rely on them being set during last render.
// TODO: revisit this when we implement resuming.
var snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState);
instance.__reactInternalSnapshotBeforeUpdate = snapshot;
stopPhaseTimer();
}
}
return;
}
case HostRoot:
case HostComponent:
case HostText:
case HostPortal:
case IncompleteClassComponent:
// Nothing to do for these component types
return;
default:
{
reactProdInvariant('163');
}
}
}
function commitHookEffectList(unmountTag, mountTag, finishedWork) {
var updateQueue = finishedWork.updateQueue;
var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
var firstEffect = lastEffect.next;
var effect = firstEffect;
do {
if ((effect.tag & unmountTag) !== NoEffect$1) {
// Unmount
var destroy = effect.destroy;
effect.destroy = undefined;
if (destroy !== undefined) {
destroy();
}
}
if ((effect.tag & mountTag) !== NoEffect$1) {
// Mount
var create = effect.create;
effect.destroy = create();
}
effect = effect.next;
} while (effect !== firstEffect);
}
}
function commitPassiveHookEffects(finishedWork) {
commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork);
commitHookEffectList(NoEffect$1, MountPassive, finishedWork);
}
function commitLifeCycles(finishedRoot, current$$1, finishedWork, committedExpirationTime) {
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case SimpleMemoComponent:
{
commitHookEffectList(UnmountLayout, MountLayout, finishedWork);
break;
}
case ClassComponent:
{
var instance = finishedWork.stateNode;
if (finishedWork.effectTag & Update) {
if (current$$1 === null) {
startPhaseTimer(finishedWork, 'componentDidMount');
// We could update instance props and state here,
// but instead we rely on them being set during last render.
// TODO: revisit this when we implement resuming.
instance.componentDidMount();
stopPhaseTimer();
} else {
var prevProps = finishedWork.elementType === finishedWork.type ? current$$1.memoizedProps : resolveDefaultProps(finishedWork.type, current$$1.memoizedProps);
var prevState = current$$1.memoizedState;
startPhaseTimer(finishedWork, 'componentDidUpdate');
// We could update instance props and state here,
// but instead we rely on them being set during last render.
// TODO: revisit this when we implement resuming.
instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate);
stopPhaseTimer();
}
}
var updateQueue = finishedWork.updateQueue;
if (updateQueue !== null) {
commitUpdateQueue(finishedWork, updateQueue, instance, committedExpirationTime);
}
return;
}
case HostRoot:
{
var _updateQueue = finishedWork.updateQueue;
if (_updateQueue !== null) {
var _instance = null;
if (finishedWork.child !== null) {
switch (finishedWork.child.tag) {
case HostComponent:
_instance = getPublicInstance(finishedWork.child.stateNode);
break;
case ClassComponent:
_instance = finishedWork.child.stateNode;
break;
}
}
commitUpdateQueue(finishedWork, _updateQueue, _instance, committedExpirationTime);
}
return;
}
case HostComponent:
{
var _instance2 = finishedWork.stateNode;
// Renderers may schedule work to be done after host components are mounted
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
// These effects should only be committed when components are first mounted,
// aka when there is no current/alternate.
if (current$$1 === null && finishedWork.effectTag & Update) {
var type = finishedWork.type;
var props = finishedWork.memoizedProps;
commitMount(_instance2, type, props, finishedWork);
}
return;
}
case HostText:
{
// We have no life-cycles associated with text.
return;
}
case HostPortal:
{
// We have no life-cycles associated with portals.
return;
}
case Profiler:
{
if (enableProfilerTimer) {
var onRender = finishedWork.memoizedProps.onRender;
if (enableSchedulerTracing) {
onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime(), finishedRoot.memoizedInteractions);
} else {
onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime());
}
}
return;
}
case SuspenseComponent:
break;
case IncompleteClassComponent:
break;
default:
{
reactProdInvariant('163');
}
}
}
function hideOrUnhideAllChildren(finishedWork, isHidden) {
if (supportsMutation) {
// We only have the top Fiber that was inserted but we need to recurse down its
var node = finishedWork;
while (true) {
if (node.tag === HostComponent) {
var instance = node.stateNode;
if (isHidden) {
hideInstance(instance);
} else {
unhideInstance(node.stateNode, node.memoizedProps);
}
} else if (node.tag === HostText) {
var _instance3 = node.stateNode;
if (isHidden) {
hideTextInstance(_instance3);
} else {
unhideTextInstance(_instance3, node.memoizedProps);
}
} else if (node.tag === SuspenseComponent && node.memoizedState !== null) {
// Found a nested Suspense component that timed out. Skip over the
var fallbackChildFragment = node.child.sibling;
fallbackChildFragment.return = node;
node = fallbackChildFragment;
continue;
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === finishedWork) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === finishedWork) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}
}
function commitAttachRef(finishedWork) {
var ref = finishedWork.ref;
if (ref !== null) {
var instance = finishedWork.stateNode;
var instanceToUse = void 0;
switch (finishedWork.tag) {
case HostComponent:
instanceToUse = getPublicInstance(instance);
break;
default:
instanceToUse = instance;
}
if (typeof ref === 'function') {
ref(instanceToUse);
} else {
ref.current = instanceToUse;
}
}
}
function commitDetachRef(current$$1) {
var currentRef = current$$1.ref;
if (currentRef !== null) {
if (typeof currentRef === 'function') {
currentRef(null);
} else {
currentRef.current = null;
}
}
}
// User-originating errors (lifecycles and refs) should not interrupt
// deletion, so don't let them throw. Host-originating errors should
// interrupt deletion, so it's okay
function commitUnmount(current$$1) {
onCommitUnmount(current$$1);
switch (current$$1.tag) {
case FunctionComponent:
case ForwardRef:
case MemoComponent:
case SimpleMemoComponent:
{
var updateQueue = current$$1.updateQueue;
if (updateQueue !== null) {
var lastEffect = updateQueue.lastEffect;
if (lastEffect !== null) {
var firstEffect = lastEffect.next;
var effect = firstEffect;
do {
var destroy = effect.destroy;
if (destroy !== undefined) {
safelyCallDestroy(current$$1, destroy);
}
effect = effect.next;
} while (effect !== firstEffect);
}
}
break;
}
case ClassComponent:
{
safelyDetachRef(current$$1);
var instance = current$$1.stateNode;
if (typeof instance.componentWillUnmount === 'function') {
safelyCallComponentWillUnmount(current$$1, instance);
}
return;
}
case HostComponent:
{
safelyDetachRef(current$$1);
return;
}
case HostPortal:
{
// TODO: this is recursive.
// We are also not using this parent because
// the portal will get pushed immediately.
if (supportsMutation) {
unmountHostComponents(current$$1);
} else if (supportsPersistence) {
emptyPortalContainer(current$$1);
}
return;
}
}
}
function commitNestedUnmounts(root) {
// While we're inside a removed host node we don't want to call
// removeChild on the inner nodes because they're removed by the top
// call anyway. We also want to call componentWillUnmount on all
// composites before this host node is removed from the tree. Therefore
var node = root;
while (true) {
commitUnmount(node);
// Visit children because they may contain more composite or host nodes.
// Skip portals because commitUnmount() currently visits them recursively.
if (node.child !== null && (
// If we use mutation we drill down into portals using commitUnmount above.
// If we don't use mutation we drill down into portals here instead.
!supportsMutation || node.tag !== HostPortal)) {
node.child.return = node;
node = node.child;
continue;
}
if (node === root) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === root) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}
function detachFiber(current$$1) {
// Cut off the return pointers to disconnect it from the tree. Ideally, we
// should clear the child pointer of the parent alternate to let this
// get GC:ed but we don't know which for sure which parent is the current
// one so we'll settle for GC:ing the subtree of this child. This child
// itself will be GC:ed when the parent updates the next time.
current$$1.return = null;
current$$1.child = null;
current$$1.memoizedState = null;
current$$1.updateQueue = null;
var alternate = current$$1.alternate;
if (alternate !== null) {
alternate.return = null;
alternate.child = null;
alternate.memoizedState = null;
alternate.updateQueue = null;
}
}
function emptyPortalContainer(current$$1) {
if (!supportsPersistence) {
return;
}
var portal = current$$1.stateNode;
var containerInfo = portal.containerInfo;
var emptyChildSet = createContainerChildSet(containerInfo);
replaceContainerChildren(containerInfo, emptyChildSet);
}
function commitContainer(finishedWork) {
if (!supportsPersistence) {
return;
}
switch (finishedWork.tag) {
case ClassComponent:
{
return;
}
case HostComponent:
{
return;
}
case HostText:
{
return;
}
case HostRoot:
case HostPortal:
{
var portalOrRoot = finishedWork.stateNode;
var containerInfo = portalOrRoot.containerInfo,
_pendingChildren = portalOrRoot.pendingChildren;
replaceContainerChildren(containerInfo, _pendingChildren);
return;
}
default:
{
reactProdInvariant('163');
}
}
}
function getHostParentFiber(fiber) {
var parent = fiber.return;
while (parent !== null) {
if (isHostParent(parent)) {
return parent;
}
parent = parent.return;
}
reactProdInvariant('160');
}
function isHostParent(fiber) {
return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal;
}
function getHostSibling(fiber) {
// We're going to search forward into the tree until we find a sibling host
// node. Unfortunately, if multiple insertions are done in a row we have to
// search past them. This leads to exponential search for the next sibling.
var node = fiber;
siblings: while (true) {
// If we didn't find anything, let's try the next sibling.
while (node.sibling === null) {
if (node.return === null || isHostParent(node.return)) {
// If we pop out of the root or hit the parent the fiber we are the
// last sibling.
return null;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
while (node.tag !== HostComponent && node.tag !== HostText && node.tag !== DehydratedSuspenseComponent) {
// If it is not host node and, we might have a host node inside it.
// Try to search down until we find one.
if (node.effectTag & Placement) {
// If we don't have a child, try the siblings instead.
continue siblings;
}
// If we don't have a child, try the siblings instead.
// We also skip portals because they are not part of this host tree.
if (node.child === null || node.tag === HostPortal) {
continue siblings;
} else {
node.child.return = node;
node = node.child;
}
}
// Check if this host node is stable or about to be placed.
if (!(node.effectTag & Placement)) {
// Found it!
return node.stateNode;
}
}
}
function commitPlacement(finishedWork) {
if (!supportsMutation) {
return;
}
// Recursively insert all host nodes into the parent.
var parentFiber = getHostParentFiber(finishedWork);
// Note: these two variables *must* always be updated together.
var parent = void 0;
var isContainer = void 0;
switch (parentFiber.tag) {
case HostComponent:
parent = parentFiber.stateNode;
isContainer = false;
break;
case HostRoot:
parent = parentFiber.stateNode.containerInfo;
isContainer = true;
break;
case HostPortal:
parent = parentFiber.stateNode.containerInfo;
isContainer = true;
break;
default:
reactProdInvariant('161');
}
if (parentFiber.effectTag & ContentReset) {
// Reset the text content of the parent before doing any insertions
resetTextContent(parent);
// Clear ContentReset from the effect tag
parentFiber.effectTag &= ~ContentReset;
}
var before = getHostSibling(finishedWork);
// We only have the top Fiber that was inserted but we need to recurse down its
// children to find all the terminal nodes.
var node = finishedWork;
while (true) {
if (node.tag === HostComponent || node.tag === HostText) {
if (before) {
if (isContainer) {
insertInContainerBefore(parent, node.stateNode, before);
} else {
insertBefore(parent, node.stateNode, before);
}
} else {
if (isContainer) {
appendChildToContainer(parent, node.stateNode);
} else {
appendChild(parent, node.stateNode);
}
}
} else if (node.tag === HostPortal) {
// If the insertion itself is a portal, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === finishedWork) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === finishedWork) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}
function unmountHostComponents(current$$1) {
// We only have the top Fiber that was deleted but we need to recurse down its
var node = current$$1;
// Each iteration, currentParent is populated with node's host parent if not
// currentParentIsValid.
var currentParentIsValid = false;
// Note: these two variables *must* always be updated together.
var currentParent = void 0;
var currentParentIsContainer = void 0;
while (true) {
if (!currentParentIsValid) {
var parent = node.return;
findParent: while (true) {
!(parent !== null) ? reactProdInvariant('160') : void 0;
switch (parent.tag) {
case HostComponent:
currentParent = parent.stateNode;
currentParentIsContainer = false;
break findParent;
case HostRoot:
currentParent = parent.stateNode.containerInfo;
currentParentIsContainer = true;
break findParent;
case HostPortal:
currentParent = parent.stateNode.containerInfo;
currentParentIsContainer = true;
break findParent;
}
parent = parent.return;
}
currentParentIsValid = true;
}
if (node.tag === HostComponent || node.tag === HostText) {
commitNestedUnmounts(node);
// After all the children have unmounted, it is now safe to remove the
// node from the tree.
if (currentParentIsContainer) {
removeChildFromContainer(currentParent, node.stateNode);
} else {
removeChild(currentParent, node.stateNode);
}
// Don't visit children because we already visited them.
} else if (enableSuspenseServerRenderer && node.tag === DehydratedSuspenseComponent) {
// Delete the dehydrated suspense boundary and all of its content.
if (currentParentIsContainer) {
clearSuspenseBoundaryFromContainer(currentParent, node.stateNode);
} else {
clearSuspenseBoundary(currentParent, node.stateNode);
}
} else if (node.tag === HostPortal) {
if (node.child !== null) {
// When we go into a portal, it becomes the parent to remove from.
// We will reassign it back when we pop the portal on the way up.
currentParent = node.stateNode.containerInfo;
currentParentIsContainer = true;
// Visit children because portals might contain host components.
node.child.return = node;
node = node.child;
continue;
}
} else {
commitUnmount(node);
// Visit children because we may find more host components below.
if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
}
if (node === current$$1) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === current$$1) {
return;
}
node = node.return;
if (node.tag === HostPortal) {
// When we go out of the portal, we need to restore the parent.
// Since we don't keep a stack of them, we will search for it.
currentParentIsValid = false;
}
}
node.sibling.return = node.return;
node = node.sibling;
}
}
function commitDeletion(current$$1) {
if (supportsMutation) {
// Recursively delete all host nodes from the parent.
// Detach refs and call componentWillUnmount() on the whole subtree.
unmountHostComponents(current$$1);
} else {
// Detach refs and call componentWillUnmount() on the whole subtree.
commitNestedUnmounts(current$$1);
}
detachFiber(current$$1);
}
function commitWork(current$$1, finishedWork) {
if (!supportsMutation) {
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case MemoComponent:
case SimpleMemoComponent:
{
// Note: We currently never use MountMutation, but useLayout uses
// UnmountMutation.
commitHookEffectList(UnmountMutation, MountMutation, finishedWork);
return;
}
}
commitContainer(finishedWork);
return;
}
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case MemoComponent:
case SimpleMemoComponent:
{
// Note: We currently never use MountMutation, but useLayout uses
// UnmountMutation.
commitHookEffectList(UnmountMutation, MountMutation, finishedWork);
return;
}
case ClassComponent:
{
return;
}
case HostComponent:
{
var instance = finishedWork.stateNode;
if (instance != null) {
// Commit the work prepared earlier.
var newProps = finishedWork.memoizedProps;
// For hydration we reuse the update path but we treat the oldProps
// as the newProps. The updatePayload will contain the real change in
// this case.
var oldProps = current$$1 !== null ? current$$1.memoizedProps : newProps;
var type = finishedWork.type;
// TODO: Type the updateQueue to be specific to host components.
var updatePayload = finishedWork.updateQueue;
finishedWork.updateQueue = null;
if (updatePayload !== null) {
commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork);
}
}
return;
}
case HostText:
{
!(finishedWork.stateNode !== null) ? reactProdInvariant('162') : void 0;
var textInstance = finishedWork.stateNode;
var newText = finishedWork.memoizedProps;
// For hydration we reuse the update path but we treat the oldProps
// as the newProps. The updatePayload will contain the real change in
// this case.
var oldText = current$$1 !== null ? current$$1.memoizedProps : newText;
commitTextUpdate(textInstance, oldText, newText);
return;
}
case HostRoot:
{
return;
}
case Profiler:
{
return;
}
case SuspenseComponent:
{
var newState = finishedWork.memoizedState;
var newDidTimeout = void 0;
var primaryChildParent = finishedWork;
if (newState === null) {
newDidTimeout = false;
} else {
newDidTimeout = true;
primaryChildParent = finishedWork.child;
if (newState.timedOutAt === NoWork) {
// If the children had not already timed out, record the time.
// This is used to compute the elapsed time during subsequent
// attempts to render the children.
newState.timedOutAt = requestCurrentTime();
}
}
if (primaryChildParent !== null) {
hideOrUnhideAllChildren(primaryChildParent, newDidTimeout);
}
// If this boundary just timed out, then it will have a set of thenables.
// For each thenable, attach a listener so that when it resolves, React
// attempts to re-render the boundary in the primary (pre-timeout) state.
var thenables = finishedWork.updateQueue;
if (thenables !== null) {
finishedWork.updateQueue = null;
var retryCache = finishedWork.stateNode;
if (retryCache === null) {
retryCache = finishedWork.stateNode = new PossiblyWeakSet$1();
}
thenables.forEach(function (thenable) {
// Memoize using the boundary fiber to prevent redundant listeners.
var retry = retryTimedOutBoundary.bind(null, finishedWork, thenable);
if (enableSchedulerTracing) {
retry = unstable_wrap(retry);
}
if (!retryCache.has(thenable)) {
retryCache.add(thenable);
thenable.then(retry, retry);
}
});
}
return;
}
case IncompleteClassComponent:
{
return;
}
default:
{
reactProdInvariant('163');
}
}
}
function commitResetTextContent(current$$1) {
if (!supportsMutation) {
return;
}
resetTextContent(current$$1.stateNode);
}
var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
function createRootErrorUpdate(fiber, errorInfo, expirationTime) {
var update = createUpdate(expirationTime);
// Unmount the root by rendering null.
update.tag = CaptureUpdate;
// Caution: React DevTools currently depends on this property
// being called "element".
update.payload = { element: null };
var error = errorInfo.value;
update.callback = function () {
onUncaughtError(error);
logError(fiber, errorInfo);
};
return update;
}
function createClassErrorUpdate(fiber, errorInfo, expirationTime) {
var update = createUpdate(expirationTime);
update.tag = CaptureUpdate;
var getDerivedStateFromError = fiber.type.getDerivedStateFromError;
if (typeof getDerivedStateFromError === 'function') {
var error = errorInfo.value;
update.payload = function () {
return getDerivedStateFromError(error);
};
}
var inst = fiber.stateNode;
if (inst !== null && typeof inst.componentDidCatch === 'function') {
update.callback = function callback() {
if (typeof getDerivedStateFromError !== 'function') {
// To preserve the preexisting retry behavior of error boundaries,
// we keep track of which ones already failed during this batch.
// This gets reset before we yield back to the browser.
// TODO: Warn in strict mode if getDerivedStateFromError is
// not defined.
markLegacyErrorBoundaryAsFailed(this);
}
var error = errorInfo.value;
var stack = errorInfo.stack;
logError(fiber, errorInfo);
this.componentDidCatch(error, {
componentStack: stack !== null ? stack : ''
});
};
}
return update;
}
function attachPingListener(root, renderExpirationTime, thenable) {
// Attach a listener to the promise to "ping" the root and retry. But
// only if one does not already exist for the current render expiration
// time (which acts like a "thread ID" here).
var pingCache = root.pingCache;
var threadIDs = void 0;
if (pingCache === null) {
pingCache = root.pingCache = new PossiblyWeakMap();
threadIDs = new Set();
pingCache.set(thenable, threadIDs);
} else {
threadIDs = pingCache.get(thenable);
if (threadIDs === undefined) {
threadIDs = new Set();
pingCache.set(thenable, threadIDs);
}
}
if (!threadIDs.has(renderExpirationTime)) {
// Memoize using the thread ID to prevent redundant listeners.
threadIDs.add(renderExpirationTime);
var ping = pingSuspendedRoot.bind(null, root, thenable, renderExpirationTime);
if (enableSchedulerTracing) {
ping = unstable_wrap(ping);
}
thenable.then(ping, ping);
}
}
function throwException(root, returnFiber, sourceFiber, value, renderExpirationTime) {
// The source fiber did not complete.
sourceFiber.effectTag |= Incomplete;
// Its effect list is no longer valid.
sourceFiber.firstEffect = sourceFiber.lastEffect = null;
if (value !== null && typeof value === 'object' && typeof value.then === 'function') {
// This is a thenable.
var thenable = value;
// Find the earliest timeout threshold of all the placeholders in the
// ancestor path. We could avoid this traversal by storing the thresholds on
// the stack, but we choose not to because we only hit this path if we're
// IO-bound (i.e. if something suspends). Whereas the stack is used even in
// the non-IO- bound case.
var _workInProgress = returnFiber;
var earliestTimeoutMs = -1;
var startTimeMs = -1;
do {
if (_workInProgress.tag === SuspenseComponent) {
var current$$1 = _workInProgress.alternate;
if (current$$1 !== null) {
var currentState = current$$1.memoizedState;
if (currentState !== null) {
// Reached a boundary that already timed out. Do not search
// any further.
var timedOutAt = currentState.timedOutAt;
startTimeMs = expirationTimeToMs(timedOutAt);
// Do not search any further.
break;
}
}
var timeoutPropMs = _workInProgress.pendingProps.maxDuration;
if (typeof timeoutPropMs === 'number') {
if (timeoutPropMs <= 0) {
earliestTimeoutMs = 0;
} else if (earliestTimeoutMs === -1 || timeoutPropMs < earliestTimeoutMs) {
earliestTimeoutMs = timeoutPropMs;
}
}
}
// If there is a DehydratedSuspenseComponent we don't have to do anything because
// if something suspends inside it, we will simply leave that as dehydrated. It
// will never timeout.
_workInProgress = _workInProgress.return;
} while (_workInProgress !== null);
// Schedule the nearest Suspense to re-render the timed out view.
_workInProgress = returnFiber;
do {
if (_workInProgress.tag === SuspenseComponent && shouldCaptureSuspense(_workInProgress)) {
// Found the nearest boundary.
// Stash the promise on the boundary fiber. If the boundary times out, we'll
var thenables = _workInProgress.updateQueue;
if (thenables === null) {
var updateQueue = new Set();
updateQueue.add(thenable);
_workInProgress.updateQueue = updateQueue;
} else {
thenables.add(thenable);
}
// If the boundary is outside of concurrent mode, we should *not*
// suspend the commit. Pretend as if the suspended component rendered
// null and keep rendering. In the commit phase, we'll schedule a
// subsequent synchronous update to re-render the Suspense.
//
// Note: It doesn't matter whether the component that suspended was
// inside a concurrent mode tree. If the Suspense is outside of it, we
// should *not* suspend the commit.
if ((_workInProgress.mode & ConcurrentMode) === NoEffect) {
_workInProgress.effectTag |= DidCapture;
// We're going to commit this fiber even though it didn't complete.
// But we shouldn't call any lifecycle methods or callbacks. Remove
// all lifecycle effect tags.
sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete);
if (sourceFiber.tag === ClassComponent) {
var currentSourceFiber = sourceFiber.alternate;
if (currentSourceFiber === null) {
// This is a new mount. Change the tag so it's not mistaken for a
// completed class component. For example, we should not call
// componentWillUnmount if it is deleted.
sourceFiber.tag = IncompleteClassComponent;
} else {
// When we try rendering again, we should not reuse the current fiber,
// since it's known to be in an inconsistent state. Use a force updte to
// prevent a bail out.
var update = createUpdate(Sync);
update.tag = ForceUpdate;
enqueueUpdate(sourceFiber, update);
}
}
// The source fiber did not complete. Mark it with Sync priority to
// indicate that it still has pending work.
sourceFiber.expirationTime = Sync;
// Exit without suspending.
return;
}
// Confirmed that the boundary is in a concurrent mode tree. Continue
// with the normal suspend path.
attachPingListener(root, renderExpirationTime, thenable);
var absoluteTimeoutMs = void 0;
if (earliestTimeoutMs === -1) {
// If no explicit threshold is given, default to an arbitrarily large
// value. The actual size doesn't matter because the threshold for the
// whole tree will be clamped to the expiration time.
absoluteTimeoutMs = maxSigned31BitInt;
} else {
if (startTimeMs === -1) {
// This suspend happened outside of any already timed-out
// placeholders. We don't know exactly when the update was
// scheduled, but we can infer an approximate start time from the
// expiration time. First, find the earliest uncommitted expiration
// time in the tree, including work that is suspended. Then subtract
// the offset used to compute an async update's expiration time.
// This will cause high priority (interactive) work to expire
// earlier than necessary, but we can account for this by adjusting
// for the Just Noticeable Difference.
var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, renderExpirationTime);
var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime);
startTimeMs = earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION;
}
absoluteTimeoutMs = startTimeMs + earliestTimeoutMs;
}
// Mark the earliest timeout in the suspended fiber's ancestor path.
// After completing the root, we'll take the largest of all the
// suspended fiber's timeouts and use it to compute a timeout for the
// whole tree.
renderDidSuspend(root, absoluteTimeoutMs, renderExpirationTime);
_workInProgress.effectTag |= ShouldCapture;
_workInProgress.expirationTime = renderExpirationTime;
return;
} else if (enableSuspenseServerRenderer && _workInProgress.tag === DehydratedSuspenseComponent) {
attachPingListener(root, renderExpirationTime, thenable);
// Since we already have a current fiber, we can eagerly add a retry listener.
var retryCache = _workInProgress.memoizedState;
if (retryCache === null) {
retryCache = _workInProgress.memoizedState = new PossiblyWeakSet();
var _current = _workInProgress.alternate;
!_current ? reactProdInvariant('319') : void 0;
_current.memoizedState = retryCache;
}
// Memoize using the boundary fiber to prevent redundant listeners.
if (!retryCache.has(thenable)) {
retryCache.add(thenable);
var retry = retryTimedOutBoundary.bind(null, _workInProgress, thenable);
if (enableSchedulerTracing) {
retry = unstable_wrap(retry);
}
thenable.then(retry, retry);
}
_workInProgress.effectTag |= ShouldCapture;
_workInProgress.expirationTime = renderExpirationTime;
return;
}
// This boundary already captured during this render. Continue to the next
// boundary.
_workInProgress = _workInProgress.return;
} while (_workInProgress !== null);
// No boundary was found. Fallthrough to error mode.
// TODO: Use invariant so the message is stripped in prod?
value = new Error((getComponentName(sourceFiber.type) || 'A React component') + ' suspended while rendering, but no fallback UI was specified.\n' + '\n' + 'Add a <Suspense fallback=...> component higher in the tree to ' + 'provide a loading indicator or placeholder to display.' + getStackByFiberInDevAndProd(sourceFiber));
}
// We didn't find a boundary that could handle this type of exception. Start
// over and traverse parent path again, this time treating the exception
// as an error.
renderDidError();
value = createCapturedValue(value, sourceFiber);
var workInProgress = returnFiber;
do {
switch (workInProgress.tag) {
case HostRoot:
{
var _errorInfo = value;
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
var _update = createRootErrorUpdate(workInProgress, _errorInfo, renderExpirationTime);
enqueueCapturedUpdate(workInProgress, _update);
return;
}
case ClassComponent:
// Capture and retry
var errorInfo = value;
var ctor = workInProgress.type;
var instance = workInProgress.stateNode;
if ((workInProgress.effectTag & DidCapture) === NoEffect && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) {
workInProgress.effectTag |= ShouldCapture;
workInProgress.expirationTime = renderExpirationTime;
// Schedule the error boundary to re-render using updated state
var _update2 = createClassErrorUpdate(workInProgress, errorInfo, renderExpirationTime);
enqueueCapturedUpdate(workInProgress, _update2);
return;
}
break;
default:
break;
}
workInProgress = workInProgress.return;
} while (workInProgress !== null);
}
function unwindWork(workInProgress, renderExpirationTime) {
switch (workInProgress.tag) {
case ClassComponent:
{
var Component = workInProgress.type;
if (isContextProvider(Component)) {
popContext(workInProgress);
}
var effectTag = workInProgress.effectTag;
if (effectTag & ShouldCapture) {
workInProgress.effectTag = effectTag & ~ShouldCapture | DidCapture;
return workInProgress;
}
return null;
}
case HostRoot:
{
popHostContainer(workInProgress);
popTopLevelContextObject(workInProgress);
var _effectTag = workInProgress.effectTag;
!((_effectTag & DidCapture) === NoEffect) ? reactProdInvariant('285') : void 0;
workInProgress.effectTag = _effectTag & ~ShouldCapture | DidCapture;
return workInProgress;
}
case HostComponent:
{
// TODO: popHydrationState
popHostContext(workInProgress);
return null;
}
case SuspenseComponent:
{
var _effectTag2 = workInProgress.effectTag;
if (_effectTag2 & ShouldCapture) {
workInProgress.effectTag = _effectTag2 & ~ShouldCapture | DidCapture;
// Captured a suspense effect. Re-render the boundary.
return workInProgress;
}
return null;
}
case DehydratedSuspenseComponent:
{
if (enableSuspenseServerRenderer) {
// TODO: popHydrationState
var _effectTag3 = workInProgress.effectTag;
if (_effectTag3 & ShouldCapture) {
workInProgress.effectTag = _effectTag3 & ~ShouldCapture | DidCapture;
// Captured a suspense effect. Re-render the boundary.
return workInProgress;
}
}
return null;
}
case HostPortal:
popHostContainer(workInProgress);
return null;
case ContextProvider:
popProvider(workInProgress);
return null;
default:
return null;
}
}
function unwindInterruptedWork(interruptedWork) {
switch (interruptedWork.tag) {
case ClassComponent:
{
var childContextTypes = interruptedWork.type.childContextTypes;
if (childContextTypes !== null && childContextTypes !== undefined) {
popContext(interruptedWork);
}
break;
}
case HostRoot:
{
popHostContainer(interruptedWork);
popTopLevelContextObject(interruptedWork);
break;
}
case HostComponent:
{
popHostContext(interruptedWork);
break;
}
case HostPortal:
popHostContainer(interruptedWork);
break;
case ContextProvider:
popProvider(interruptedWork);
break;
default:
break;
}
}
var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner;
if (enableSchedulerTracing) {
// Provide explicit error message when production+profiling bundle of e.g. react-dom
// is used with production (non-profiling) bundle of scheduler/tracing
!(__interactionsRef != null && __interactionsRef.current != null) ? reactProdInvariant('302') : void 0;
}
// Used to ensure computeUniqueAsyncExpiration is monotonically decreasing.
var lastUniqueAsyncExpiration = Sync - 1;
var isWorking = false;
// The next work in progress fiber that we're currently working on.
var nextUnitOfWork = null;
var nextRoot = null;
// The time at which we're currently rendering work.
var nextRenderExpirationTime = NoWork;
var nextLatestAbsoluteTimeoutMs = -1;
var nextRenderDidError = false;
// The next fiber with an effect that we're currently committing.
var nextEffect = null;
var isCommitting$1 = false;
var rootWithPendingPassiveEffects = null;
var passiveEffectCallbackHandle = null;
var passiveEffectCallback = null;
var legacyErrorBoundariesThatAlreadyFailed = null;
// Used for performance tracking.
var interruptedBy = null;
function resetStack() {
if (nextUnitOfWork !== null) {
var interruptedWork = nextUnitOfWork.return;
while (interruptedWork !== null) {
unwindInterruptedWork(interruptedWork);
interruptedWork = interruptedWork.return;
}
}
nextRoot = null;
nextRenderExpirationTime = NoWork;
nextLatestAbsoluteTimeoutMs = -1;
nextRenderDidError = false;
nextUnitOfWork = null;
}
function commitAllHostEffects() {
while (nextEffect !== null) {
recordEffect();
var effectTag = nextEffect.effectTag;
if (effectTag & ContentReset) {
commitResetTextContent(nextEffect);
}
if (effectTag & Ref) {
var current$$1 = nextEffect.alternate;
if (current$$1 !== null) {
commitDetachRef(current$$1);
}
}
// The following switch statement is only concerned about placement,
// updates, and deletions. To avoid needing to add a case for every
// possible bitmap value, we remove the secondary effects from the
// effect tag and switch on that value.
var primaryEffectTag = effectTag & (Placement | Update | Deletion);
switch (primaryEffectTag) {
case Placement:
{
commitPlacement(nextEffect);
// Clear the "placement" from effect tag so that we know that this is inserted, before
// any life-cycles like componentDidMount gets called.
// TODO: findDOMNode doesn't rely on this any more but isMounted
// does and isMounted is deprecated anyway so we should be able
// to kill this.
nextEffect.effectTag &= ~Placement;
break;
}
case PlacementAndUpdate:
{
// Placement
commitPlacement(nextEffect);
// Clear the "placement" from effect tag so that we know that this is inserted, before
// any life-cycles like componentDidMount gets called.
nextEffect.effectTag &= ~Placement;
// Update
var _current = nextEffect.alternate;
commitWork(_current, nextEffect);
break;
}
case Update:
{
var _current2 = nextEffect.alternate;
commitWork(_current2, nextEffect);
break;
}
case Deletion:
{
commitDeletion(nextEffect);
break;
}
}
nextEffect = nextEffect.nextEffect;
}
}
function commitBeforeMutationLifecycles() {
while (nextEffect !== null) {
var effectTag = nextEffect.effectTag;
if (effectTag & Snapshot) {
recordEffect();
var current$$1 = nextEffect.alternate;
commitBeforeMutationLifeCycles(current$$1, nextEffect);
}
nextEffect = nextEffect.nextEffect;
}
}
function commitAllLifeCycles(finishedRoot, committedExpirationTime) {
while (nextEffect !== null) {
var effectTag = nextEffect.effectTag;
if (effectTag & (Update | Callback)) {
recordEffect();
var current$$1 = nextEffect.alternate;
commitLifeCycles(finishedRoot, current$$1, nextEffect, committedExpirationTime);
}
if (effectTag & Ref) {
recordEffect();
commitAttachRef(nextEffect);
}
if (effectTag & Passive) {
rootWithPendingPassiveEffects = finishedRoot;
}
nextEffect = nextEffect.nextEffect;
}
}
function commitPassiveEffects(root, firstEffect) {
rootWithPendingPassiveEffects = null;
passiveEffectCallbackHandle = null;
passiveEffectCallback = null;
// Set this to true to prevent re-entrancy
var previousIsRendering = isRendering;
isRendering = true;
var effect = firstEffect;
do {
if (effect.effectTag & Passive) {
var didError = false;
var error = void 0;
{
try {
commitPassiveHookEffects(effect);
} catch (e) {
didError = true;
error = e;
}
}
if (didError) {
captureCommitPhaseError(effect, error);
}
}
effect = effect.nextEffect;
} while (effect !== null);
isRendering = previousIsRendering;
// Check if work was scheduled by one of the effects
var rootExpirationTime = root.expirationTime;
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
// Flush any sync work that was scheduled by effects
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
}
}
function isAlreadyFailedLegacyErrorBoundary(instance) {
return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance);
}
function markLegacyErrorBoundaryAsFailed(instance) {
if (legacyErrorBoundariesThatAlreadyFailed === null) {
legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);
} else {
legacyErrorBoundariesThatAlreadyFailed.add(instance);
}
}
function flushPassiveEffects() {
if (passiveEffectCallbackHandle !== null) {
cancelPassiveEffects(passiveEffectCallbackHandle);
}
if (passiveEffectCallback !== null) {
// We call the scheduled callback instead of commitPassiveEffects directly
// to ensure tracing works correctly.
passiveEffectCallback();
}
}
function commitRoot(root, finishedWork) {
isWorking = true;
isCommitting$1 = true;
startCommitTimer();
!(root.current !== finishedWork) ? reactProdInvariant('177') : void 0;
var committedExpirationTime = root.pendingCommitExpirationTime;
!(committedExpirationTime !== NoWork) ? reactProdInvariant('261') : void 0;
root.pendingCommitExpirationTime = NoWork;
// Update the pending priority levels to account for the work that we are
// about to commit. This needs to happen before calling the lifecycles, since
// they may schedule additional updates.
var updateExpirationTimeBeforeCommit = finishedWork.expirationTime;
var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime;
var earliestRemainingTimeBeforeCommit = childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit ? childExpirationTimeBeforeCommit : updateExpirationTimeBeforeCommit;
markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit);
var prevInteractions = null;
if (enableSchedulerTracing) {
// Restore any pending interactions at this point,
// So that cascading work triggered during the render phase will be accounted for.
prevInteractions = __interactionsRef.current;
__interactionsRef.current = root.memoizedInteractions;
}
// Reset this to null before calling lifecycles
ReactCurrentOwner$2.current = null;
var firstEffect = void 0;
if (finishedWork.effectTag > PerformedWork) {
// A fiber's effect list consists only of its children, not itself. So if
// the root has an effect, we need to add it to the end of the list. The
// resulting list is the set that would belong to the root's parent, if
// it had one; that is, all the effects in the tree including the root.
if (finishedWork.lastEffect !== null) {
finishedWork.lastEffect.nextEffect = finishedWork;
firstEffect = finishedWork.firstEffect;
} else {
firstEffect = finishedWork;
}
} else {
// There is no effect on the root.
firstEffect = finishedWork.firstEffect;
}
prepareForCommit(root.containerInfo);
// Invoke instances of getSnapshotBeforeUpdate before mutation.
nextEffect = firstEffect;
startCommitSnapshotEffectsTimer();
while (nextEffect !== null) {
var didError = false;
var error = void 0;
{
try {
commitBeforeMutationLifecycles();
} catch (e) {
didError = true;
error = e;
}
}
if (didError) {
!(nextEffect !== null) ? reactProdInvariant('178') : void 0;
captureCommitPhaseError(nextEffect, error);
// Clean-up
if (nextEffect !== null) {
nextEffect = nextEffect.nextEffect;
}
}
}
stopCommitSnapshotEffectsTimer();
if (enableProfilerTimer) {
// Mark the current commit time to be shared by all Profilers in this batch.
// This enables them to be grouped later.
recordCommitTime();
}
// Commit all the side-effects within a tree. We'll do this in two passes.
// The first pass performs all the host insertions, updates, deletions and
// ref unmounts.
nextEffect = firstEffect;
startCommitHostEffectsTimer();
while (nextEffect !== null) {
var _didError = false;
var _error = void 0;
{
try {
commitAllHostEffects();
} catch (e) {
_didError = true;
_error = e;
}
}
if (_didError) {
!(nextEffect !== null) ? reactProdInvariant('178') : void 0;
captureCommitPhaseError(nextEffect, _error);
// Clean-up
if (nextEffect !== null) {
nextEffect = nextEffect.nextEffect;
}
}
}
stopCommitHostEffectsTimer();
resetAfterCommit(root.containerInfo);
// The work-in-progress tree is now the current tree. This must come after
// the first pass of the commit phase, so that the previous tree is still
// current during componentWillUnmount, but before the second pass, so that
// the finished work is current during componentDidMount/Update.
root.current = finishedWork;
// In the second pass we'll perform all life-cycles and ref callbacks.
// Life-cycles happen as a separate pass so that all placements, updates,
// and deletions in the entire tree have already been invoked.
// This pass also triggers any renderer-specific initial effects.
nextEffect = firstEffect;
startCommitLifeCyclesTimer();
while (nextEffect !== null) {
var _didError2 = false;
var _error2 = void 0;
{
try {
commitAllLifeCycles(root, committedExpirationTime);
} catch (e) {
_didError2 = true;
_error2 = e;
}
}
if (_didError2) {
!(nextEffect !== null) ? reactProdInvariant('178') : void 0;
captureCommitPhaseError(nextEffect, _error2);
if (nextEffect !== null) {
nextEffect = nextEffect.nextEffect;
}
}
}
if (firstEffect !== null && rootWithPendingPassiveEffects !== null) {
// This commit included a passive effect. These do not need to fire until
// after the next paint. Schedule an callback to fire them in an async
// event. To ensure serial execution, the callback will be flushed early if
// we enter rootWithPendingPassiveEffects commit phase before then.
var callback = commitPassiveEffects.bind(null, root, firstEffect);
if (enableSchedulerTracing) {
// TODO: Avoid this extra callback by mutating the tracing ref directly,
// like we do at the beginning of commitRoot. I've opted not to do that
// here because that code is still in flux.
callback = unstable_wrap(callback);
}
passiveEffectCallbackHandle = unstable_runWithPriority(unstable_NormalPriority, function () {
return schedulePassiveEffects(callback);
});
passiveEffectCallback = callback;
}
isCommitting$1 = false;
isWorking = false;
stopCommitLifeCyclesTimer();
stopCommitTimer();
onCommitRoot(finishedWork.stateNode);
var updateExpirationTimeAfterCommit = finishedWork.expirationTime;
var childExpirationTimeAfterCommit = finishedWork.childExpirationTime;
var earliestRemainingTimeAfterCommit = childExpirationTimeAfterCommit > updateExpirationTimeAfterCommit ? childExpirationTimeAfterCommit : updateExpirationTimeAfterCommit;
if (earliestRemainingTimeAfterCommit === NoWork) {
// If there's no remaining work, we can clear the set of already failed
// error boundaries.
legacyErrorBoundariesThatAlreadyFailed = null;
}
onCommit(root, earliestRemainingTimeAfterCommit);
if (enableSchedulerTracing) {
__interactionsRef.current = prevInteractions;
var subscriber = void 0;
try {
subscriber = __subscriberRef.current;
if (subscriber !== null && root.memoizedInteractions.size > 0) {
var threadID = computeThreadID(committedExpirationTime, root.interactionThreadID);
subscriber.onWorkStopped(root.memoizedInteractions, threadID);
}
} catch (error) {
// It's not safe for commitRoot() to throw.
// Store the error for now and we'll re-throw in finishRendering().
if (!hasUnhandledError) {
hasUnhandledError = true;
unhandledError = error;
}
} finally {
// Clear completed interactions from the pending Map.
// Unless the render was suspended or cascading work was scheduled,
// In which case– leave pending interactions until the subsequent render.
var pendingInteractionMap = root.pendingInteractionMap;
pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) {
// Only decrement the pending interaction count if we're done.
// If there's still work at the current priority,
// That indicates that we are waiting for suspense data.
if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) {
pendingInteractionMap.delete(scheduledExpirationTime);
scheduledInteractions.forEach(function (interaction) {
interaction.__count--;
if (subscriber !== null && interaction.__count === 0) {
try {
subscriber.onInteractionScheduledWorkCompleted(interaction);
} catch (error) {
// It's not safe for commitRoot() to throw.
// Store the error for now and we'll re-throw in finishRendering().
if (!hasUnhandledError) {
hasUnhandledError = true;
unhandledError = error;
}
}
}
});
}
});
}
}
}
function resetChildExpirationTime(workInProgress, renderTime) {
if (renderTime !== Never && workInProgress.childExpirationTime === Never) {
// The children of this component are hidden. Don't bubble their
// expiration times.
return;
}
var newChildExpirationTime = NoWork;
// Bubble up the earliest expiration time.
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
// We're in profiling mode.
// Let's use this same traversal to update the render durations.
var actualDuration = workInProgress.actualDuration;
var treeBaseDuration = workInProgress.selfBaseDuration;
// When a fiber is cloned, its actualDuration is reset to 0.
// This value will only be updated if work is done on the fiber (i.e. it doesn't bailout).
// When work is done, it should bubble to the parent's actualDuration.
// If the fiber has not been cloned though, (meaning no work was done),
// Then this value will reflect the amount of time spent working on a previous render.
// In that case it should not bubble.
// We determine whether it was cloned by comparing the child pointer.
var shouldBubbleActualDurations = workInProgress.alternate === null || workInProgress.child !== workInProgress.alternate.child;
var child = workInProgress.child;
while (child !== null) {
var childUpdateExpirationTime = child.expirationTime;
var childChildExpirationTime = child.childExpirationTime;
if (childUpdateExpirationTime > newChildExpirationTime) {
newChildExpirationTime = childUpdateExpirationTime;
}
if (childChildExpirationTime > newChildExpirationTime) {
newChildExpirationTime = childChildExpirationTime;
}
if (shouldBubbleActualDurations) {
actualDuration += child.actualDuration;
}
treeBaseDuration += child.treeBaseDuration;
child = child.sibling;
}
workInProgress.actualDuration = actualDuration;
workInProgress.treeBaseDuration = treeBaseDuration;
} else {
var _child = workInProgress.child;
while (_child !== null) {
var _childUpdateExpirationTime = _child.expirationTime;
var _childChildExpirationTime = _child.childExpirationTime;
if (_childUpdateExpirationTime > newChildExpirationTime) {
newChildExpirationTime = _childUpdateExpirationTime;
}
if (_childChildExpirationTime > newChildExpirationTime) {
newChildExpirationTime = _childChildExpirationTime;
}
_child = _child.sibling;
}
}
workInProgress.childExpirationTime = newChildExpirationTime;
}
function completeUnitOfWork(workInProgress) {
// Attempt to complete the current unit of work, then move to the
// next sibling. If there are no more siblings, return to the
// parent fiber.
while (true) {
// The current, flushed, state of this fiber is the alternate.
// Ideally nothing should rely on this, but relying on it here
// means that we don't need an additional field on the work in
// progress.
var current$$1 = workInProgress.alternate;
var returnFiber = workInProgress.return;
var siblingFiber = workInProgress.sibling;
if ((workInProgress.effectTag & Incomplete) === NoEffect) {
nextUnitOfWork = workInProgress;
if (enableProfilerTimer) {
if (workInProgress.mode & ProfileMode) {
startProfilerTimer(workInProgress);
}
nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime);
if (workInProgress.mode & ProfileMode) {
// Update render duration assuming we didn't error.
stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);
}
} else {
nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime);
}
stopWorkTimer(workInProgress);
resetChildExpirationTime(workInProgress, nextRenderExpirationTime);
if (nextUnitOfWork !== null) {
// Completing this fiber spawned new work. Work on that next.
return nextUnitOfWork;
}
if (returnFiber !== null &&
// Do not append effects to parents if a sibling failed to complete
(returnFiber.effectTag & Incomplete) === NoEffect) {
// Append all the effects of the subtree and this fiber onto the effect
// list of the parent. The completion order of the children affects the
// side-effect order.
if (returnFiber.firstEffect === null) {
returnFiber.firstEffect = workInProgress.firstEffect;
}
if (workInProgress.lastEffect !== null) {
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;
}
returnFiber.lastEffect = workInProgress.lastEffect;
}
// If this fiber had side-effects, we append it AFTER the children's
// side-effects. We can perform certain side-effects earlier if
// needed, by doing multiple passes over the effect list. We don't want
// to schedule our own side-effect on our own list because if end up
// reusing children we'll schedule this effect onto itself since we're
// at the end.
var effectTag = workInProgress.effectTag;
// Skip both NoWork and PerformedWork tags when creating the effect list.
// PerformedWork effect is read by React DevTools but shouldn't be committed.
if (effectTag > PerformedWork) {
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = workInProgress;
} else {
returnFiber.firstEffect = workInProgress;
}
returnFiber.lastEffect = workInProgress;
}
}
if (siblingFiber !== null) {
// If there is more work to do in this returnFiber, do that next.
return siblingFiber;
} else if (returnFiber !== null) {
// If there's no more work in this returnFiber. Complete the returnFiber.
workInProgress = returnFiber;
continue;
} else {
// We've reached the root.
return null;
}
} else {
if (enableProfilerTimer && workInProgress.mode & ProfileMode) {
// Record the render duration for the fiber that errored.
stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);
// Include the time spent working on failed children before continuing.
var actualDuration = workInProgress.actualDuration;
var child = workInProgress.child;
while (child !== null) {
actualDuration += child.actualDuration;
child = child.sibling;
}
workInProgress.actualDuration = actualDuration;
}
// This fiber did not complete because something threw. Pop values off
// the stack without entering the complete phase. If this is a boundary,
// capture values if possible.
var next = unwindWork(workInProgress, nextRenderExpirationTime);
// Because this fiber did not complete, don't reset its expiration time.
if (workInProgress.effectTag & DidCapture) {
// Restarting an error boundary
stopFailedWorkTimer(workInProgress);
} else {
stopWorkTimer(workInProgress);
}
if (next !== null) {
stopWorkTimer(workInProgress);
next.effectTag &= HostEffectMask;
return next;
}
if (returnFiber !== null) {
// Mark the parent fiber as incomplete and clear its effect list.
returnFiber.firstEffect = returnFiber.lastEffect = null;
returnFiber.effectTag |= Incomplete;
}
if (siblingFiber !== null) {
// If there is more work to do in this returnFiber, do that next.
return siblingFiber;
} else if (returnFiber !== null) {
// If there's no more work in this returnFiber. Complete the returnFiber.
workInProgress = returnFiber;
continue;
} else {
return null;
}
}
}
// Without this explicit null return Flow complains of invalid return type
// TODO Remove the above while(true) loop
// eslint-disable-next-line no-unreachable
return null;
}
function performUnitOfWork(workInProgress) {
// The current, flushed, state of this fiber is the alternate.
// Ideally nothing should rely on this, but relying on it here
// means that we don't need an additional field on the work in
// progress.
var current$$1 = workInProgress.alternate;
// See if beginning this work spawns more work.
startWorkTimer(workInProgress);
var next = void 0;
if (enableProfilerTimer) {
if (workInProgress.mode & ProfileMode) {
startProfilerTimer(workInProgress);
}
next = beginWork(current$$1, workInProgress, nextRenderExpirationTime);
workInProgress.memoizedProps = workInProgress.pendingProps;
if (workInProgress.mode & ProfileMode) {
// Record the render duration assuming we didn't bailout (or error).
stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true);
}
} else {
next = beginWork(current$$1, workInProgress, nextRenderExpirationTime);
workInProgress.memoizedProps = workInProgress.pendingProps;
}
if (next === null) {
// If this doesn't spawn new work, complete the current work.
next = completeUnitOfWork(workInProgress);
}
ReactCurrentOwner$2.current = null;
return next;
}
function workLoop(isYieldy) {
if (!isYieldy) {
// Flush work without yielding
while (nextUnitOfWork !== null) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
} else {
// Flush asynchronous work until there's a higher priority event
while (nextUnitOfWork !== null && !shouldYieldToRenderer()) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
}
function renderRoot(root, isYieldy) {
!!isWorking ? reactProdInvariant('243') : void 0;
flushPassiveEffects();
isWorking = true;
var previousDispatcher = ReactCurrentDispatcher.current;
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var expirationTime = root.nextExpirationTimeToWorkOn;
// Check if we're starting from a fresh stack, or if we're resuming from
// previously yielded work.
if (expirationTime !== nextRenderExpirationTime || root !== nextRoot || nextUnitOfWork === null) {
// Reset the stack and start working from the root.
resetStack();
nextRoot = root;
nextRenderExpirationTime = expirationTime;
nextUnitOfWork = createWorkInProgress(nextRoot.current, null, nextRenderExpirationTime);
root.pendingCommitExpirationTime = NoWork;
if (enableSchedulerTracing) {
// Determine which interactions this batch of work currently includes,
// So that we can accurately attribute time spent working on it,
var interactions = new Set();
root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) {
if (scheduledExpirationTime >= expirationTime) {
scheduledInteractions.forEach(function (interaction) {
return interactions.add(interaction);
});
}
});
// Store the current set of interactions on the FiberRoot for a few reasons:
// We can re-use it in hot functions like renderRoot() without having to recalculate it.
// We will also use it in commitWork() to pass to any Profiler onRender() hooks.
// This also provides DevTools with a way to access it when the onCommitRoot() hook is called.
root.memoizedInteractions = interactions;
if (interactions.size > 0) {
var subscriber = __subscriberRef.current;
if (subscriber !== null) {
var threadID = computeThreadID(expirationTime, root.interactionThreadID);
try {
subscriber.onWorkStarted(interactions, threadID);
} catch (error) {
// Work thrown by an interaction tracing subscriber should be rethrown,
// But only once it's safe (to avoid leaving the scheduler in an invalid state).
// Store the error for now and we'll re-throw in finishRendering().
if (!hasUnhandledError) {
hasUnhandledError = true;
unhandledError = error;
}
}
}
}
}
}
var prevInteractions = null;
if (enableSchedulerTracing) {
// We're about to start new traced work.
// Restore pending interactions so cascading work triggered during the render phase will be accounted for.
prevInteractions = __interactionsRef.current;
__interactionsRef.current = root.memoizedInteractions;
}
var didFatal = false;
startWorkLoopTimer(nextUnitOfWork);
do {
try {
workLoop(isYieldy);
} catch (thrownValue) {
resetContextDependences();
resetHooks();
// Reset in case completion throws.
// This is only used in DEV and when replaying is on.
if (nextUnitOfWork === null) {
// This is a fatal error.
didFatal = true;
onUncaughtError(thrownValue);
} else {
if (enableProfilerTimer && nextUnitOfWork.mode & ProfileMode) {
// Record the time spent rendering before an error was thrown.
// This avoids inaccurate Profiler durations in the case of a suspended render.
stopProfilerTimerIfRunningAndRecordDelta(nextUnitOfWork, true);
}
!(nextUnitOfWork !== null) ? reactProdInvariant('271') : void 0;
var sourceFiber = nextUnitOfWork;
var returnFiber = sourceFiber.return;
if (returnFiber === null) {
// This is the root. The root could capture its own errors. However,
// we don't know if it errors before or after we pushed the host
// context. This information is needed to avoid a stack mismatch.
// Because we're not sure, treat this as a fatal error. We could track
// which phase it fails in, but doesn't seem worth it. At least
// for now.
didFatal = true;
onUncaughtError(thrownValue);
} else {
throwException(root, returnFiber, sourceFiber, thrownValue, nextRenderExpirationTime);
nextUnitOfWork = completeUnitOfWork(sourceFiber);
continue;
}
}
}
break;
} while (true);
if (enableSchedulerTracing) {
// Traced work is done for now; restore the previous interactions.
__interactionsRef.current = prevInteractions;
}
// We're done performing work. Time to clean up.
isWorking = false;
ReactCurrentDispatcher.current = previousDispatcher;
resetContextDependences();
resetHooks();
// Yield back to main thread.
if (didFatal) {
var _didCompleteRoot = false;
stopWorkLoopTimer(interruptedBy, _didCompleteRoot);
interruptedBy = null;
// There was a fatal error.
nextRoot = null;
onFatal(root);
return;
}
if (nextUnitOfWork !== null) {
// There's still remaining async work in this tree, but we ran out of time
// in the current frame. Yield back to the renderer. Unless we're
// interrupted by a higher priority update, we'll continue later from where
// we left off.
var _didCompleteRoot2 = false;
stopWorkLoopTimer(interruptedBy, _didCompleteRoot2);
interruptedBy = null;
onYield(root);
return;
}
// We completed the whole tree.
var didCompleteRoot = true;
stopWorkLoopTimer(interruptedBy, didCompleteRoot);
var rootWorkInProgress = root.current.alternate;
!(rootWorkInProgress !== null) ? reactProdInvariant('281') : void 0;
// `nextRoot` points to the in-progress root. A non-null value indicates
// that we're in the middle of an async render. Set it to null to indicate
// there's no more work to be done in the current batch.
nextRoot = null;
interruptedBy = null;
if (nextRenderDidError) {
// There was an error
if (hasLowerPriorityWork(root, expirationTime)) {
// There's lower priority work. If so, it may have the effect of fixing
// the exception that was just thrown. Exit without committing. This is
// similar to a suspend, but without a timeout because we're not waiting
// for a promise to resolve. React will restart at the lower
// priority level.
markSuspendedPriorityLevel(root, expirationTime);
var suspendedExpirationTime = expirationTime;
var rootExpirationTime = root.expirationTime;
onSuspend(root, rootWorkInProgress, suspendedExpirationTime, rootExpirationTime, -1 // Indicates no timeout
);
return;
} else if (
// There's no lower priority work, but we're rendering asynchronously.
// Synchronously attempt to render the same level one more time. This is
// similar to a suspend, but without a timeout because we're not waiting
// for a promise to resolve.
!root.didError && isYieldy) {
root.didError = true;
var _suspendedExpirationTime = root.nextExpirationTimeToWorkOn = expirationTime;
var _rootExpirationTime = root.expirationTime = Sync;
onSuspend(root, rootWorkInProgress, _suspendedExpirationTime, _rootExpirationTime, -1 // Indicates no timeout
);
return;
}
}
if (isYieldy && nextLatestAbsoluteTimeoutMs !== -1) {
// The tree was suspended.
var _suspendedExpirationTime2 = expirationTime;
markSuspendedPriorityLevel(root, _suspendedExpirationTime2);
// Find the earliest uncommitted expiration time in the tree, including
// work that is suspended. The timeout threshold cannot be longer than
// the overall expiration.
var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, expirationTime);
var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime);
if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) {
nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs;
}
// Subtract the current time from the absolute timeout to get the number
// of milliseconds until the timeout. In other words, convert an absolute
// timestamp to a relative time. This is the value that is passed
// to `setTimeout`.
var currentTimeMs = expirationTimeToMs(requestCurrentTime());
var msUntilTimeout = nextLatestAbsoluteTimeoutMs - currentTimeMs;
msUntilTimeout = msUntilTimeout < 0 ? 0 : msUntilTimeout;
// TODO: Account for the Just Noticeable Difference
var _rootExpirationTime2 = root.expirationTime;
onSuspend(root, rootWorkInProgress, _suspendedExpirationTime2, _rootExpirationTime2, msUntilTimeout);
return;
}
// Ready to commit.
onComplete(root, rootWorkInProgress, expirationTime);
}
function captureCommitPhaseError(sourceFiber, value) {
var expirationTime = Sync;
var fiber = sourceFiber.return;
while (fiber !== null) {
switch (fiber.tag) {
case ClassComponent:
var ctor = fiber.type;
var instance = fiber.stateNode;
if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {
var errorInfo = createCapturedValue(value, sourceFiber);
var update = createClassErrorUpdate(fiber, errorInfo, expirationTime);
enqueueUpdate(fiber, update);
scheduleWork(fiber, expirationTime);
return;
}
break;
case HostRoot:
{
var _errorInfo = createCapturedValue(value, sourceFiber);
var _update = createRootErrorUpdate(fiber, _errorInfo, expirationTime);
enqueueUpdate(fiber, _update);
scheduleWork(fiber, expirationTime);
return;
}
}
fiber = fiber.return;
}
if (sourceFiber.tag === HostRoot) {
// Error was thrown at the root. There is no parent, so the root
// itself should capture it.
var rootFiber = sourceFiber;
var _errorInfo2 = createCapturedValue(value, rootFiber);
var _update2 = createRootErrorUpdate(rootFiber, _errorInfo2, expirationTime);
enqueueUpdate(rootFiber, _update2);
scheduleWork(rootFiber, expirationTime);
}
}
function computeThreadID(expirationTime, interactionThreadID) {
// Interaction threads are unique per root and expiration time.
return expirationTime * 1000 + interactionThreadID;
}
// Creates a unique async expiration time.
function computeUniqueAsyncExpiration() {
var currentTime = requestCurrentTime();
var result = computeAsyncExpiration(currentTime);
if (result >= lastUniqueAsyncExpiration) {
// Since we assume the current time monotonically increases, we only hit
// this branch when computeUniqueAsyncExpiration is fired multiple times
// within a 200ms window (or whatever the async bucket size is).
result = lastUniqueAsyncExpiration - 1;
}
lastUniqueAsyncExpiration = result;
return lastUniqueAsyncExpiration;
}
function computeExpirationForFiber(currentTime, fiber) {
var priorityLevel = unstable_getCurrentPriorityLevel();
var expirationTime = void 0;
if ((fiber.mode & ConcurrentMode) === NoContext) {
// Outside of concurrent mode, updates are always synchronous.
expirationTime = Sync;
} else if (isWorking && !isCommitting$1) {
// During render phase, updates expire during as the current render.
expirationTime = nextRenderExpirationTime;
} else {
switch (priorityLevel) {
case unstable_ImmediatePriority:
expirationTime = Sync;
break;
case unstable_UserBlockingPriority:
expirationTime = computeInteractiveExpiration(currentTime);
break;
case unstable_NormalPriority:
// This is a normal, concurrent update
expirationTime = computeAsyncExpiration(currentTime);
break;
case unstable_LowPriority:
case unstable_IdlePriority:
expirationTime = Never;
break;
default:
reactProdInvariant('313');
}
// If we're in the middle of rendering a tree, do not update at the same
// expiration time that is already rendering.
if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
expirationTime -= 1;
}
}
// Keep track of the lowest pending interactive expiration time. This
// allows us to synchronously flush all interactive updates
// when needed.
// TODO: Move this to renderer?
if (priorityLevel === unstable_UserBlockingPriority && (lowestPriorityPendingInteractiveExpirationTime === NoWork || expirationTime < lowestPriorityPendingInteractiveExpirationTime)) {
lowestPriorityPendingInteractiveExpirationTime = expirationTime;
}
return expirationTime;
}
function renderDidSuspend(root, absoluteTimeoutMs, suspendedTime) {
// Schedule the timeout.
if (absoluteTimeoutMs >= 0 && nextLatestAbsoluteTimeoutMs < absoluteTimeoutMs) {
nextLatestAbsoluteTimeoutMs = absoluteTimeoutMs;
}
}
function renderDidError() {
nextRenderDidError = true;
}
function pingSuspendedRoot(root, thenable, pingTime) {
// A promise that previously suspended React from committing has resolved.
// If React is still suspended, try again at the previous level (pingTime).
var pingCache = root.pingCache;
if (pingCache !== null) {
// The thenable resolved, so we no longer need to memoize, because it will
// never be thrown again.
pingCache.delete(thenable);
}
if (nextRoot !== null && nextRenderExpirationTime === pingTime) {
// Received a ping at the same priority level at which we're currently
// rendering. Restart from the root.
nextRoot = null;
} else {
// Confirm that the root is still suspended at this level. Otherwise exit.
if (isPriorityLevelSuspended(root, pingTime)) {
// Ping at the original level
markPingedPriorityLevel(root, pingTime);
var rootExpirationTime = root.expirationTime;
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
}
}
}
function retryTimedOutBoundary(boundaryFiber, thenable) {
// The boundary fiber (a Suspense component) previously timed out and was
// rendered in its fallback state. One of the promises that suspended it has
// resolved, which means at least part of the tree was likely unblocked. Try
var retryCache = void 0;
if (enableSuspenseServerRenderer) {
switch (boundaryFiber.tag) {
case SuspenseComponent:
retryCache = boundaryFiber.stateNode;
break;
case DehydratedSuspenseComponent:
retryCache = boundaryFiber.memoizedState;
break;
default:
reactProdInvariant('314');
}
} else {
retryCache = boundaryFiber.stateNode;
}
if (retryCache !== null) {
// The thenable resolved, so we no longer need to memoize, because it will
// never be thrown again.
retryCache.delete(thenable);
}
var currentTime = requestCurrentTime();
var retryTime = computeExpirationForFiber(currentTime, boundaryFiber);
var root = scheduleWorkToRoot(boundaryFiber, retryTime);
if (root !== null) {
markPendingPriorityLevel(root, retryTime);
var rootExpirationTime = root.expirationTime;
if (rootExpirationTime !== NoWork) {
requestWork(root, rootExpirationTime);
}
}
}
function scheduleWorkToRoot(fiber, expirationTime) {
recordScheduleUpdate();
if (fiber.expirationTime < expirationTime) {
fiber.expirationTime = expirationTime;
}
var alternate = fiber.alternate;
if (alternate !== null && alternate.expirationTime < expirationTime) {
alternate.expirationTime = expirationTime;
}
// Walk the parent path to the root and update the child expiration time.
var node = fiber.return;
var root = null;
if (node === null && fiber.tag === HostRoot) {
root = fiber.stateNode;
} else {
while (node !== null) {
alternate = node.alternate;
if (node.childExpirationTime < expirationTime) {
node.childExpirationTime = expirationTime;
if (alternate !== null && alternate.childExpirationTime < expirationTime) {
alternate.childExpirationTime = expirationTime;
}
} else if (alternate !== null && alternate.childExpirationTime < expirationTime) {
alternate.childExpirationTime = expirationTime;
}
if (node.return === null && node.tag === HostRoot) {
root = node.stateNode;
break;
}
node = node.return;
}
}
if (enableSchedulerTracing) {
if (root !== null) {
var interactions = __interactionsRef.current;
if (interactions.size > 0) {
var pendingInteractionMap = root.pendingInteractionMap;
var pendingInteractions = pendingInteractionMap.get(expirationTime);
if (pendingInteractions != null) {
interactions.forEach(function (interaction) {
if (!pendingInteractions.has(interaction)) {
// Update the pending async work count for previously unscheduled interaction.
interaction.__count++;
}
pendingInteractions.add(interaction);
});
} else {
pendingInteractionMap.set(expirationTime, new Set(interactions));
// Update the pending async work count for the current interactions.
interactions.forEach(function (interaction) {
interaction.__count++;
});
}
var subscriber = __subscriberRef.current;
if (subscriber !== null) {
var threadID = computeThreadID(expirationTime, root.interactionThreadID);
subscriber.onWorkScheduled(interactions, threadID);
}
}
}
}
return root;
}
function scheduleWork(fiber, expirationTime) {
var root = scheduleWorkToRoot(fiber, expirationTime);
if (root === null) {
return;
}
if (!isWorking && nextRenderExpirationTime !== NoWork && expirationTime > nextRenderExpirationTime) {
// This is an interruption. (Used for performance tracking.)
interruptedBy = fiber;
resetStack();
}
markPendingPriorityLevel(root, expirationTime);
if (
// If we're in the render phase, we don't need to schedule this root
// for an update, because we'll do it before we exit...
!isWorking || isCommitting$1 ||
// ...unless this is a different root than the one we're rendering.
nextRoot !== root) {
var rootExpirationTime = root.expirationTime;
requestWork(root, rootExpirationTime);
}
if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
// Reset this back to zero so subsequent updates don't throw.
nestedUpdateCount = 0;
reactProdInvariant('185');
}
}
function syncUpdates(fn, a, b, c, d) {
return unstable_runWithPriority(unstable_ImmediatePriority, function () {
return fn(a, b, c, d);
});
}
// TODO: Everything below this is written as if it has been lifted to the
// renderers. I'll do this in a follow-up.
// Linked-list of roots
var firstScheduledRoot = null;
var lastScheduledRoot = null;
var callbackExpirationTime = NoWork;
var callbackID = void 0;
var isRendering = false;
var nextFlushedRoot = null;
var nextFlushedExpirationTime = NoWork;
var lowestPriorityPendingInteractiveExpirationTime = NoWork;
var hasUnhandledError = false;
var unhandledError = null;
var isBatchingUpdates = false;
var isUnbatchingUpdates = false;
var completedBatches = null;
var originalStartTimeMs = unstable_now();
var currentRendererTime = msToExpirationTime(originalStartTimeMs);
var currentSchedulerTime = currentRendererTime;
// Use these to prevent an infinite loop of nested updates
var NESTED_UPDATE_LIMIT = 50;
var nestedUpdateCount = 0;
var lastCommittedRootDuringThisBatch = null;
function recomputeCurrentRendererTime() {
var currentTimeMs = unstable_now() - originalStartTimeMs;
currentRendererTime = msToExpirationTime(currentTimeMs);
}
function scheduleCallbackWithExpirationTime(root, expirationTime) {
if (callbackExpirationTime !== NoWork) {
// A callback is already scheduled. Check its expiration time (timeout).
if (expirationTime < callbackExpirationTime) {
// Existing callback has sufficient timeout. Exit.
return;
} else {
if (callbackID !== null) {
// Existing callback has insufficient timeout. Cancel and schedule a
// new one.
unstable_cancelCallback(callbackID);
}
}
// The request callback timer is already running. Don't start a new one.
} else {
startRequestCallbackTimer();
}
callbackExpirationTime = expirationTime;
var currentMs = unstable_now() - originalStartTimeMs;
var expirationTimeMs = expirationTimeToMs(expirationTime);
var timeout = expirationTimeMs - currentMs;
callbackID = unstable_scheduleCallback(performAsyncWork, { timeout: timeout });
}
// For every call to renderRoot, one of onFatal, onComplete, onSuspend, and
// onYield is called upon exiting. We use these in lieu of returning a tuple.
// I've also chosen not to inline them into renderRoot because these will
// eventually be lifted into the renderer.
function onFatal(root) {
root.finishedWork = null;
}
function onComplete(root, finishedWork, expirationTime) {
root.pendingCommitExpirationTime = expirationTime;
root.finishedWork = finishedWork;
}
function onSuspend(root, finishedWork, suspendedExpirationTime, rootExpirationTime, msUntilTimeout) {
root.expirationTime = rootExpirationTime;
if (msUntilTimeout === 0 && !shouldYieldToRenderer()) {
// Don't wait an additional tick. Commit the tree immediately.
root.pendingCommitExpirationTime = suspendedExpirationTime;
root.finishedWork = finishedWork;
} else if (msUntilTimeout > 0) {
// Wait `msUntilTimeout` milliseconds before committing.
root.timeoutHandle = scheduleTimeout(onTimeout.bind(null, root, finishedWork, suspendedExpirationTime), msUntilTimeout);
}
}
function onYield(root) {
root.finishedWork = null;
}
function onTimeout(root, finishedWork, suspendedExpirationTime) {
// The root timed out. Commit it.
root.pendingCommitExpirationTime = suspendedExpirationTime;
root.finishedWork = finishedWork;
// Read the current time before entering the commit phase. We can be
// certain this won't cause tearing related to batching of event updates
// because we're at the top of a timer event.
recomputeCurrentRendererTime();
currentSchedulerTime = currentRendererTime;
flushRoot(root, suspendedExpirationTime);
}
function onCommit(root, expirationTime) {
root.expirationTime = expirationTime;
root.finishedWork = null;
}
function requestCurrentTime() {
// requestCurrentTime is called by the scheduler to compute an expiration
// time.
//
// Expiration times are computed by adding to the current time (the start
// time). However, if two updates are scheduled within the same event, we
// should treat their start times as simultaneous, even if the actual clock
// time has advanced between the first and second call.
// In other words, because expiration times determine how updates are batched,
// we want all updates of like priority that occur within the same event to
// receive the same expiration time. Otherwise we get tearing.
//
// We keep track of two separate times: the current "renderer" time and the
// current "scheduler" time. The renderer time can be updated whenever; it
// only exists to minimize the calls performance.now.
//
// But the scheduler time can only be updated if there's no pending work, or
// if we know for certain that we're not in the middle of an event.
if (isRendering) {
// We're already rendering. Return the most recently read time.
return currentSchedulerTime;
}
// Check if there's pending work.
findHighestPriorityRoot();
if (nextFlushedExpirationTime === NoWork || nextFlushedExpirationTime === Never) {
// If there's no pending work, or if the pending work is offscreen, we can
// read the current time without risk of tearing.
recomputeCurrentRendererTime();
currentSchedulerTime = currentRendererTime;
return currentSchedulerTime;
}
// There's already pending work. We might be in the middle of a browser
// event. If we were to read the current time, it could cause multiple updates
// within the same event to receive different expiration times, leading to
// tearing. Return the last read time. During the next idle callback, the
// time will be updated.
return currentSchedulerTime;
}
// requestWork is called by the scheduler whenever a root receives an update.
// It's up to the renderer to call renderRoot at some point in the future.
function requestWork(root, expirationTime) {
addRootToSchedule(root, expirationTime);
if (isRendering) {
// Prevent reentrancy. Remaining work will be scheduled at the end of
// the currently rendering batch.
return;
}
if (isBatchingUpdates) {
// Flush work at the end of the batch.
if (isUnbatchingUpdates) {
// ...unless we're inside unbatchedUpdates, in which case we should
// flush it now.
nextFlushedRoot = root;
nextFlushedExpirationTime = Sync;
performWorkOnRoot(root, Sync, false);
}
return;
}
// TODO: Get rid of Sync and use current time?
if (expirationTime === Sync) {
performSyncWork();
} else {
scheduleCallbackWithExpirationTime(root, expirationTime);
}
}
function addRootToSchedule(root, expirationTime) {
// Add the root to the schedule.
// Check if this root is already part of the schedule.
if (root.nextScheduledRoot === null) {
// This root is not already scheduled. Add it.
root.expirationTime = expirationTime;
if (lastScheduledRoot === null) {
firstScheduledRoot = lastScheduledRoot = root;
root.nextScheduledRoot = root;
} else {
lastScheduledRoot.nextScheduledRoot = root;
lastScheduledRoot = root;
lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
}
} else {
// This root is already scheduled, but its priority may have increased.
var remainingExpirationTime = root.expirationTime;
if (expirationTime > remainingExpirationTime) {
// Update the priority.
root.expirationTime = expirationTime;
}
}
}
function findHighestPriorityRoot() {
var highestPriorityWork = NoWork;
var highestPriorityRoot = null;
if (lastScheduledRoot !== null) {
var previousScheduledRoot = lastScheduledRoot;
var root = firstScheduledRoot;
while (root !== null) {
var remainingExpirationTime = root.expirationTime;
if (remainingExpirationTime === NoWork) {
// This root no longer has work. Remove it from the scheduler.
// TODO: This check is redudant, but Flow is confused by the branch
// below where we set lastScheduledRoot to null, even though we break
// from the loop right after.
!(previousScheduledRoot !== null && lastScheduledRoot !== null) ? reactProdInvariant('244') : void 0;
if (root === root.nextScheduledRoot) {
// This is the only root in the list.
root.nextScheduledRoot = null;
firstScheduledRoot = lastScheduledRoot = null;
break;
} else if (root === firstScheduledRoot) {
// This is the first root in the list.
var next = root.nextScheduledRoot;
firstScheduledRoot = next;
lastScheduledRoot.nextScheduledRoot = next;
root.nextScheduledRoot = null;
} else if (root === lastScheduledRoot) {
// This is the last root in the list.
lastScheduledRoot = previousScheduledRoot;
lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
root.nextScheduledRoot = null;
break;
} else {
previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot;
root.nextScheduledRoot = null;
}
root = previousScheduledRoot.nextScheduledRoot;
} else {
if (remainingExpirationTime > highestPriorityWork) {
// Update the priority, if it's higher
highestPriorityWork = remainingExpirationTime;
highestPriorityRoot = root;
}
if (root === lastScheduledRoot) {
break;
}
if (highestPriorityWork === Sync) {
// Sync is highest priority by definition so
// we can stop searching.
break;
}
previousScheduledRoot = root;
root = root.nextScheduledRoot;
}
}
}
nextFlushedRoot = highestPriorityRoot;
nextFlushedExpirationTime = highestPriorityWork;
}
// TODO: This wrapper exists because many of the older tests (the ones that use
// flushDeferredPri) rely on the number of times `shouldYield` is called. We
// should get rid of it.
var didYield = false;
function shouldYieldToRenderer() {
if (didYield) {
return true;
}
if (unstable_shouldYield()) {
didYield = true;
return true;
}
return false;
}
function performAsyncWork() {
try {
if (!shouldYieldToRenderer()) {
// The callback timed out. That means at least one update has expired.
// Iterate through the root schedule. If they contain expired work, set
// the next render expiration time to the current time. This has the effect
// of flushing all expired work in a single batch, instead of flushing each
// level one at a time.
if (firstScheduledRoot !== null) {
recomputeCurrentRendererTime();
var root = firstScheduledRoot;
do {
didExpireAtExpirationTime(root, currentRendererTime);
// The root schedule is circular, so this is never null.
root = root.nextScheduledRoot;
} while (root !== firstScheduledRoot);
}
}
performWork(NoWork, true);
} finally {
didYield = false;
}
}
function performSyncWork() {
performWork(Sync, false);
}
function performWork(minExpirationTime, isYieldy) {
// Keep working on roots until there's no more work, or until there's a higher
// priority event.
findHighestPriorityRoot();
if (isYieldy) {
recomputeCurrentRendererTime();
currentSchedulerTime = currentRendererTime;
if (enableUserTimingAPI) {
var didExpire = nextFlushedExpirationTime > currentRendererTime;
var timeout = expirationTimeToMs(nextFlushedExpirationTime);
stopRequestCallbackTimer(didExpire, timeout);
}
while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime && !(didYield && currentRendererTime > nextFlushedExpirationTime)) {
performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, currentRendererTime > nextFlushedExpirationTime);
findHighestPriorityRoot();
recomputeCurrentRendererTime();
currentSchedulerTime = currentRendererTime;
}
} else {
while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime) {
performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false);
findHighestPriorityRoot();
}
}
// We're done flushing work. Either we ran out of time in this callback,
// or there's no more work left with sufficient priority.
// If we're inside a callback, set this to false since we just completed it.
if (isYieldy) {
callbackExpirationTime = NoWork;
callbackID = null;
}
// If there's work left over, schedule a new callback.
if (nextFlushedExpirationTime !== NoWork) {
scheduleCallbackWithExpirationTime(nextFlushedRoot, nextFlushedExpirationTime);
}
// Clean-up.
finishRendering();
}
function flushRoot(root, expirationTime) {
!!isRendering ? reactProdInvariant('253') : void 0;
// Perform work on root as if the given expiration time is the current time.
// This has the effect of synchronously flushing all work up to and
// including the given time.
nextFlushedRoot = root;
nextFlushedExpirationTime = expirationTime;
performWorkOnRoot(root, expirationTime, false);
// Flush any sync work that was scheduled by lifecycles
performSyncWork();
}
function finishRendering() {
nestedUpdateCount = 0;
lastCommittedRootDuringThisBatch = null;
if (completedBatches !== null) {
var batches = completedBatches;
completedBatches = null;
for (var i = 0; i < batches.length; i++) {
var batch = batches[i];
try {
batch._onComplete();
} catch (error) {
if (!hasUnhandledError) {
hasUnhandledError = true;
unhandledError = error;
}
}
}
}
if (hasUnhandledError) {
var error = unhandledError;
unhandledError = null;
hasUnhandledError = false;
throw error;
}
}
function performWorkOnRoot(root, expirationTime, isYieldy) {
!!isRendering ? reactProdInvariant('245') : void 0;
isRendering = true;
// Check if this is async work or sync/expired work.
if (!isYieldy) {
// Flush work without yielding.
// TODO: Non-yieldy work does not necessarily imply expired work. A renderer
// may want to perform some work without yielding, but also without
// requiring the root to complete (by triggering placeholders).
var finishedWork = root.finishedWork;
if (finishedWork !== null) {
// This root is already complete. We can commit it.
completeRoot(root, finishedWork, expirationTime);
} else {
root.finishedWork = null;
// If this root previously suspended, clear its existing timeout, since
// we're about to try rendering again.
var timeoutHandle = root.timeoutHandle;
if (timeoutHandle !== noTimeout) {
root.timeoutHandle = noTimeout;
// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
cancelTimeout(timeoutHandle);
}
renderRoot(root, isYieldy);
finishedWork = root.finishedWork;
if (finishedWork !== null) {
// We've completed the root. Commit it.
completeRoot(root, finishedWork, expirationTime);
}
}
} else {
// Flush async work.
var _finishedWork = root.finishedWork;
if (_finishedWork !== null) {
// This root is already complete. We can commit it.
completeRoot(root, _finishedWork, expirationTime);
} else {
root.finishedWork = null;
// If this root previously suspended, clear its existing timeout, since
// we're about to try rendering again.
var _timeoutHandle = root.timeoutHandle;
if (_timeoutHandle !== noTimeout) {
root.timeoutHandle = noTimeout;
// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above
cancelTimeout(_timeoutHandle);
}
renderRoot(root, isYieldy);
_finishedWork = root.finishedWork;
if (_finishedWork !== null) {
// We've completed the root. Check the if we should yield one more time
// before committing.
if (!shouldYieldToRenderer()) {
// Still time left. Commit the root.
completeRoot(root, _finishedWork, expirationTime);
} else {
// There's no time left. Mark this root as complete. We'll come
// back and commit it later.
root.finishedWork = _finishedWork;
}
}
}
}
isRendering = false;
}
function completeRoot(root, finishedWork, expirationTime) {
// Check if there's a batch that matches this expiration time.
var firstBatch = root.firstBatch;
if (firstBatch !== null && firstBatch._expirationTime >= expirationTime) {
if (completedBatches === null) {
completedBatches = [firstBatch];
} else {
completedBatches.push(firstBatch);
}
if (firstBatch._defer) {
// This root is blocked from committing by a batch. Unschedule it until
// we receive another update.
root.finishedWork = finishedWork;
root.expirationTime = NoWork;
return;
}
}
// Commit the root.
root.finishedWork = null;
// Check if this is a nested update (a sync update scheduled during the
// commit phase).
if (root === lastCommittedRootDuringThisBatch) {
// If the next root is the same as the previous root, this is a nested
// update. To prevent an infinite loop, increment the nested update count.
nestedUpdateCount++;
} else {
// Reset whenever we switch roots.
lastCommittedRootDuringThisBatch = root;
nestedUpdateCount = 0;
}
unstable_runWithPriority(unstable_ImmediatePriority, function () {
commitRoot(root, finishedWork);
});
}
function onUncaughtError(error) {
!(nextFlushedRoot !== null) ? reactProdInvariant('246') : void 0;
// Unschedule this root so we don't work on it again until there's
// another update.
nextFlushedRoot.expirationTime = NoWork;
if (!hasUnhandledError) {
hasUnhandledError = true;
unhandledError = error;
}
}
// TODO: Batching should be implemented at the renderer level, not inside
// the reconciler.
function batchedUpdates$1(fn, a) {
var previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return fn(a);
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
}
}
}
// TODO: Batching should be implemented at the renderer level, not inside
// the reconciler.
function unbatchedUpdates(fn, a) {
if (isBatchingUpdates && !isUnbatchingUpdates) {
isUnbatchingUpdates = true;
try {
return fn(a);
} finally {
isUnbatchingUpdates = false;
}
}
return fn(a);
}
// TODO: Batching should be implemented at the renderer level, not within
// the reconciler.
function flushSync(fn, a) {
!!isRendering ? reactProdInvariant('187') : void 0;
var previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return syncUpdates(fn, a);
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
performSyncWork();
}
}
function interactiveUpdates$1(fn, a, b) {
// If there are any pending interactive updates, synchronously flush them.
// This needs to happen before we read any handlers, because the effect of
// the previous event may influence which handlers are called during
// this event.
if (!isBatchingUpdates && !isRendering && lowestPriorityPendingInteractiveExpirationTime !== NoWork) {
// Synchronously flush pending interactive updates.
performWork(lowestPriorityPendingInteractiveExpirationTime, false);
lowestPriorityPendingInteractiveExpirationTime = NoWork;
}
var previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return unstable_runWithPriority(unstable_UserBlockingPriority, function () {
return fn(a, b);
});
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
}
}
}
function flushInteractiveUpdates$1() {
if (!isRendering && lowestPriorityPendingInteractiveExpirationTime !== NoWork) {
// Synchronously flush pending interactive updates.
performWork(lowestPriorityPendingInteractiveExpirationTime, false);
lowestPriorityPendingInteractiveExpirationTime = NoWork;
}
}
function flushControlled(fn) {
var previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
syncUpdates(fn);
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performSyncWork();
}
}
}
function getContextForSubtree(parentComponent) {
if (!parentComponent) {
return emptyContextObject;
}
var fiber = get(parentComponent);
var parentContext = findCurrentUnmaskedContext(fiber);
if (fiber.tag === ClassComponent) {
var Component = fiber.type;
if (isContextProvider(Component)) {
return processChildContext(fiber, Component, parentContext);
}
}
return parentContext;
}
function scheduleRootUpdate(current$$1, element, expirationTime, callback) {
var update = createUpdate(expirationTime);
// Caution: React DevTools currently depends on this property
// being called "element".
update.payload = { element: element };
callback = callback === undefined ? null : callback;
if (callback !== null) {
update.callback = callback;
}
flushPassiveEffects();
enqueueUpdate(current$$1, update);
scheduleWork(current$$1, expirationTime);
return expirationTime;
}
function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) {
// TODO: If this is a nested container, this won't be the root.
var current$$1 = container.current;
var context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
return scheduleRootUpdate(current$$1, element, expirationTime, callback);
}
function findHostInstance(component) {
var fiber = get(component);
if (fiber === undefined) {
if (typeof component.render === 'function') {
reactProdInvariant('188');
} else {
reactProdInvariant('268', Object.keys(component));
}
}
var hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
return null;
}
return hostFiber.stateNode;
}
function createContainer(containerInfo, isConcurrent, hydrate) {
return createFiberRoot(containerInfo, isConcurrent, hydrate);
}
function updateContainer(element, container, parentComponent, callback) {
var current$$1 = container.current;
var currentTime = requestCurrentTime();
var expirationTime = computeExpirationForFiber(currentTime, current$$1);
return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback);
}
function getPublicRootInstance(container) {
var containerFiber = container.current;
if (!containerFiber.child) {
return null;
}
switch (containerFiber.child.tag) {
case HostComponent:
return getPublicInstance(containerFiber.child.stateNode);
default:
return containerFiber.child.stateNode;
}
}
var overrideProps = null;
function injectIntoDevTools(devToolsConfig) {
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;
return injectInternals(_assign({}, devToolsConfig, {
overrideProps: overrideProps,
currentDispatcherRef: ReactCurrentDispatcher,
findHostInstanceByFiber: function (fiber) {
var hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
return null;
}
return hostFiber.stateNode;
},
findFiberByHostInstance: function (instance) {
if (!findFiberByHostInstance) {
// Might not be implemented by the renderer.
return null;
}
return findFiberByHostInstance(instance);
}
}));
}
// This file intentionally does *not* have the Flow annotation.
// Don't add it. See `./inline-typed.js` for an explanation.
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;
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
};
}
// TODO: this is special because it gets imported during build.
var ReactVersion = '16.8.6';
// TODO: This type is shared between the reconciler and ReactDOM, but will
// eventually be lifted out to the renderer.
var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
setRestoreImplementation(restoreControlledState$1);
function ReactBatch(root) {
var expirationTime = computeUniqueAsyncExpiration();
this._expirationTime = expirationTime;
this._root = root;
this._next = null;
this._callbacks = null;
this._didComplete = false;
this._hasChildren = false;
this._children = null;
this._defer = true;
}
ReactBatch.prototype.render = function (children) {
!this._defer ? reactProdInvariant('250') : void 0;
this._hasChildren = true;
this._children = children;
var internalRoot = this._root._internalRoot;
var expirationTime = this._expirationTime;
var work = new ReactWork();
updateContainerAtExpirationTime(children, internalRoot, null, expirationTime, work._onCommit);
return work;
};
ReactBatch.prototype.then = function (onComplete) {
if (this._didComplete) {
onComplete();
return;
}
var callbacks = this._callbacks;
if (callbacks === null) {
callbacks = this._callbacks = [];
}
callbacks.push(onComplete);
};
ReactBatch.prototype.commit = function () {
var internalRoot = this._root._internalRoot;
var firstBatch = internalRoot.firstBatch;
!(this._defer && firstBatch !== null) ? reactProdInvariant('251') : void 0;
if (!this._hasChildren) {
// This batch is empty. Return.
this._next = null;
this._defer = false;
return;
}
var expirationTime = this._expirationTime;
// Ensure this is the first batch in the list.
if (firstBatch !== this) {
// This batch is not the earliest batch. We need to move it to the front.
// Update its expiration time to be the expiration time of the earliest
// batch, so that we can flush it without flushing the other batches.
if (this._hasChildren) {
expirationTime = this._expirationTime = firstBatch._expirationTime;
// Rendering this batch again ensures its children will be the final state
// when we flush (updates are processed in insertion order: last
// update wins).
// TODO: This forces a restart. Should we print a warning?
this.render(this._children);
}
// Remove the batch from the list.
var previous = null;
var batch = firstBatch;
while (batch !== this) {
previous = batch;
batch = batch._next;
}
!(previous !== null) ? reactProdInvariant('251') : void 0;
previous._next = batch._next;
// Add it to the front.
this._next = firstBatch;
firstBatch = internalRoot.firstBatch = this;
}
// Synchronously flush all the work up to this batch's expiration time.
this._defer = false;
flushRoot(internalRoot, expirationTime);
// Pop the batch from the list.
var next = this._next;
this._next = null;
firstBatch = internalRoot.firstBatch = next;
// Append the next earliest batch's children to the update queue.
if (firstBatch !== null && firstBatch._hasChildren) {
firstBatch.render(firstBatch._children);
}
};
ReactBatch.prototype._onComplete = function () {
if (this._didComplete) {
return;
}
this._didComplete = true;
var callbacks = this._callbacks;
if (callbacks === null) {
return;
}
// TODO: Error handling.
for (var i = 0; i < callbacks.length; i++) {
var _callback = callbacks[i];
_callback();
}
};
function ReactWork() {
this._callbacks = null;
this._didCommit = false;
// TODO: Avoid need to bind by replacing callbacks in the update queue with
// list of Work objects.
this._onCommit = this._onCommit.bind(this);
}
ReactWork.prototype.then = function (onCommit) {
if (this._didCommit) {
onCommit();
return;
}
var callbacks = this._callbacks;
if (callbacks === null) {
callbacks = this._callbacks = [];
}
callbacks.push(onCommit);
};
ReactWork.prototype._onCommit = function () {
if (this._didCommit) {
return;
}
this._didCommit = true;
var callbacks = this._callbacks;
if (callbacks === null) {
return;
}
// TODO: Error handling.
for (var i = 0; i < callbacks.length; i++) {
var _callback2 = callbacks[i];
!(typeof _callback2 === 'function') ? reactProdInvariant('191', _callback2) : void 0;
_callback2();
}
};
function ReactRoot(container, isConcurrent, hydrate) {
var root = createContainer(container, isConcurrent, hydrate);
this._internalRoot = root;
}
ReactRoot.prototype.render = function (children, callback) {
var root = this._internalRoot;
var work = new ReactWork();
callback = callback === undefined ? null : callback;
if (callback !== null) {
work.then(callback);
}
updateContainer(children, root, null, work._onCommit);
return work;
};
ReactRoot.prototype.unmount = function (callback) {
var root = this._internalRoot;
var work = new ReactWork();
callback = callback === undefined ? null : callback;
if (callback !== null) {
work.then(callback);
}
updateContainer(null, root, null, work._onCommit);
return work;
};
ReactRoot.prototype.legacy_renderSubtreeIntoContainer = function (parentComponent, children, callback) {
var root = this._internalRoot;
var work = new ReactWork();
callback = callback === undefined ? null : callback;
if (callback !== null) {
work.then(callback);
}
updateContainer(children, root, parentComponent, work._onCommit);
return work;
};
ReactRoot.prototype.createBatch = function () {
var batch = new ReactBatch(this);
var expirationTime = batch._expirationTime;
var internalRoot = this._internalRoot;
var firstBatch = internalRoot.firstBatch;
if (firstBatch === null) {
internalRoot.firstBatch = batch;
batch._next = null;
} else {
// Insert sorted by expiration time then insertion order
var insertAfter = null;
var insertBefore = firstBatch;
while (insertBefore !== null && insertBefore._expirationTime >= expirationTime) {
insertAfter = insertBefore;
insertBefore = insertBefore._next;
}
batch._next = insertBefore;
if (insertAfter !== null) {
insertAfter._next = batch;
}
}
return batch;
};
/**
* True if the supplied DOM node is a valid node element.
*
* @param {?DOMElement} node The candidate DOM node.
* @return {boolean} True if the DOM is a valid DOM node.
* @internal
*/
function isValidContainer(node) {
return !!(node && (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE || node.nodeType === COMMENT_NODE && node.nodeValue === ' react-mount-point-unstable '));
}
function getReactRootElementInContainer(container) {
if (!container) {
return null;
}
if (container.nodeType === DOCUMENT_NODE) {
return container.documentElement;
} else {
return container.firstChild;
}
}
function shouldHydrateDueToLegacyHeuristic(container) {
var rootElement = getReactRootElementInContainer(container);
return !!(rootElement && rootElement.nodeType === ELEMENT_NODE && rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME));
}
setBatchingImplementation(batchedUpdates$1, interactiveUpdates$1, flushInteractiveUpdates$1);
function legacyCreateRootFromDOMContainer(container, forceHydrate) {
var shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
// First clear any existing content.
if (!shouldHydrate) {
var rootSibling = void 0;
while (rootSibling = container.lastChild) {
container.removeChild(rootSibling);
}
}
var isConcurrent = false;
return new ReactRoot(container, isConcurrent, shouldHydrate);
}
function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
var root = container._reactRootContainer;
if (!root) {
// Initial mount
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
if (typeof callback === 'function') {
var originalCallback = callback;
callback = function () {
var instance = getPublicRootInstance(root._internalRoot);
originalCallback.call(instance);
};
}
// Initial mount should not be batched.
unbatchedUpdates(function () {
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
} else {
root.render(children, callback);
}
});
} else {
if (typeof callback === 'function') {
var _originalCallback = callback;
callback = function () {
var instance = getPublicRootInstance(root._internalRoot);
_originalCallback.call(instance);
};
}
// Update
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
} else {
root.render(children, callback);
}
}
return getPublicRootInstance(root._internalRoot);
}
function createPortal$$1(children, container) {
var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
!isValidContainer(container) ? reactProdInvariant('200') : void 0;
// TODO: pass ReactDOM portal implementation as third argument
return createPortal$1(children, container, null, key);
}
var ReactDOM = {
createPortal: createPortal$$1,
findDOMNode: function (componentOrElement) {
if (componentOrElement == null) {
return null;
}
if (componentOrElement.nodeType === ELEMENT_NODE) {
return componentOrElement;
}
return findHostInstance(componentOrElement);
},
hydrate: function (element, container, callback) {
!isValidContainer(container) ? reactProdInvariant('200') : void 0;
return legacyRenderSubtreeIntoContainer(null, element, container, true, callback);
},
render: function (element, container, callback) {
!isValidContainer(container) ? reactProdInvariant('200') : void 0;
return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
},
unstable_renderSubtreeIntoContainer: function (parentComponent, element, containerNode, callback) {
!isValidContainer(containerNode) ? reactProdInvariant('200') : void 0;
!(parentComponent != null && has(parentComponent)) ? reactProdInvariant('38') : void 0;
return legacyRenderSubtreeIntoContainer(parentComponent, element, containerNode, false, callback);
},
unmountComponentAtNode: function (container) {
!isValidContainer(container) ? reactProdInvariant('40') : void 0;
if (container._reactRootContainer) {
unbatchedUpdates(function () {
legacyRenderSubtreeIntoContainer(null, null, container, false, function () {
container._reactRootContainer = null;
});
});
// If you call unmountComponentAtNode twice in quick succession, you'll
// get `true` twice. That's probably fine?
return true;
} else {
return false;
}
},
// Temporary alias since we already shipped React 16 RC with it.
// TODO: remove in React 17.
unstable_createPortal: function () {
return createPortal$$1.apply(undefined, arguments);
},
unstable_batchedUpdates: batchedUpdates$1,
unstable_interactiveUpdates: interactiveUpdates$1,
flushSync: flushSync,
unstable_createRoot: createRoot,
unstable_flushControlled: flushControlled,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
// Keep in sync with ReactDOMUnstableNativeDependencies.js
// and ReactTestUtils.js. This is an array for better minification.
Events: [getInstanceFromNode$1, getNodeFromInstance$1, getFiberCurrentPropsFromNode$1, injection.injectEventPluginsByName, eventNameDispatchConfigs, accumulateTwoPhaseDispatches, accumulateDirectDispatches, enqueueStateRestore, restoreStateIfNeeded, dispatchEvent, runEventsInBatch]
}
};
function createRoot(container, options) {
var functionName = enableStableConcurrentModeAPIs ? 'createRoot' : 'unstable_createRoot';
!isValidContainer(container) ? reactProdInvariant('299', functionName) : void 0;
var hydrate = options != null && options.hydrate === true;
return new ReactRoot(container, true, hydrate);
}
if (enableStableConcurrentModeAPIs) {
ReactDOM.createRoot = createRoot;
ReactDOM.unstable_createRoot = undefined;
}
var foundDevTools = injectIntoDevTools({
findFiberByHostInstance: getClosestInstanceFromNode,
bundleType: 0,
version: ReactVersion,
rendererPackageName: 'react-dom'
});
var ReactDOM$2 = ({
default: ReactDOM
});
var ReactDOM$3 = ( ReactDOM$2 && ReactDOM ) || ReactDOM$2;
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
var reactDom = ReactDOM$3.default || ReactDOM$3;
return reactDom;
})));