diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index 4b68730cb3a34..d4688db04f1d3 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -909c6dacfde06b87fa22f2e8506c47124cf982b5 +73b6435ca4e0c3ae3aac8126509a82420a84f0d7 diff --git a/compiled/facebook-www/React-dev.modern.js b/compiled/facebook-www/React-dev.modern.js index ee7762bb5db01..b721df3b97355 100644 --- a/compiled/facebook-www/React-dev.modern.js +++ b/compiled/facebook-www/React-dev.modern.js @@ -27,7 +27,7 @@ if ( } "use strict"; -var ReactVersion = "18.3.0-www-modern-e3dcc95d"; +var ReactVersion = "18.3.0-www-modern-11df97fe"; // ATTENTION // When adding new symbols to this file, diff --git a/compiled/facebook-www/ReactART-dev.classic.js b/compiled/facebook-www/ReactART-dev.classic.js index ad85031365d35..454bf8e96b3ed 100644 --- a/compiled/facebook-www/ReactART-dev.classic.js +++ b/compiled/facebook-www/ReactART-dev.classic.js @@ -69,7 +69,7 @@ function _assertThisInitialized(self) { return self; } -var ReactVersion = "18.3.0-www-classic-7d98bb40"; +var ReactVersion = "18.3.0-www-classic-dfeb256e"; var LegacyRoot = 0; var ConcurrentRoot = 1; @@ -2521,24 +2521,24 @@ function lanesToEventPriority(lanes) { // Renderers that don't support hydration // can re-export everything from this module. -function shim$1() { +function shim$2() { throw new Error( "The current renderer does not support hydration. " + "This error is likely caused by a bug in React. " + "Please file an issue." ); } // Hydration (when unsupported) -var isSuspenseInstancePending = shim$1; -var isSuspenseInstanceFallback = shim$1; -var getSuspenseInstanceFallbackErrorDetails = shim$1; -var registerSuspenseInstanceRetry = shim$1; -var clearSuspenseBoundary = shim$1; -var clearSuspenseBoundaryFromContainer = shim$1; -var errorHydratingContainer = shim$1; +var isSuspenseInstancePending = shim$2; +var isSuspenseInstanceFallback = shim$2; +var getSuspenseInstanceFallbackErrorDetails = shim$2; +var registerSuspenseInstanceRetry = shim$2; +var clearSuspenseBoundary = shim$2; +var clearSuspenseBoundaryFromContainer = shim$2; +var errorHydratingContainer = shim$2; // Renderers that don't support React Scopes // can re-export everything from this module. -function shim() { +function shim$1() { throw new Error( "The current renderer does not support React Scopes. " + "This error is likely caused by a bug in React. " + @@ -2546,8 +2546,19 @@ function shim() { ); } // React Scopes (when unsupported) -var prepareScopeUpdate = shim; -var getInstanceFromScope = shim; +var prepareScopeUpdate = shim$1; +var getInstanceFromScope = shim$1; + +// Renderers that don't support hydration +// can re-export everything from this module. +function shim() { + throw new Error( + "The current renderer does not support Resources. " + + "This error is likely caused by a bug in React. " + + "Please file an issue." + ); +} // Resources (when unsupported) +var suspendResource = shim; var pooledTransform = new Transform(); var NO_CONTEXT = {}; @@ -2923,6 +2934,9 @@ function unhideTextInstance(textInstance, text) { function getInstanceFromNode(node) { throw new Error("Not implemented."); } +function maySuspendCommit(type, props) { + return false; +} function preloadInstance(type, props) { // Return true to indicate it's already loaded return true; @@ -5576,6 +5590,13 @@ function trackUsedThenable(thenableState, thenable, index) { } } } +function suspendCommit() { + // This extra indirection only exists so it can handle passing + // noopSuspenseyCommitThenable through to throwException. + // TODO: Factor the thenable check out of throwException + suspendedThenable = noopSuspenseyCommitThenable; + throw SuspenseyCommitException; +} // This is used to track the actual thenable that suspended so it can be // passed to the rest of the Suspense implementation — which, for historical // reasons, expects to receive a thenable. @@ -17687,16 +17708,28 @@ function preloadInstanceAndSuspendIfNeeded( props, renderLanes ) { - // Ask the renderer if this instance should suspend the commit. - { - // If this flag was set previously, we can remove it. The flag represents - // whether this particular set of props might ever need to suspend. The - // safest thing to do is for maySuspendCommit to always return true, but - // if the renderer is reasonably confident that the underlying resource - // won't be evicted, it can return false as a performance optimization. - workInProgress.flags &= ~SuspenseyCommit; - return; - } // Mark this fiber with a flag. We use this right before the commit phase to + workInProgress.flags |= SuspenseyCommit; // Check if we're rendering at a "non-urgent" priority. This is the same + // check that `useDeferredValue` does to determine whether it needs to + // defer. This is partly for gradual adoption purposes (i.e. shouldn't start + // suspending until you opt in with startTransition or Suspense) but it + // also happens to be the desired behavior for the concrete use cases we've + // thought of so far, like CSS loading, fonts, images, etc. + // TODO: We may decide to expose a way to force a fallback even during a + // sync update. + + if (!includesOnlyNonUrgentLanes(renderLanes)); + else { + // Preload the instance + var isReady = preloadInstance(); + + if (!isReady) { + if (shouldRemainOnPreviousScreen()); + else { + // Trigger a fallback rather than block the render. + suspendCommit(); + } + } + } } function scheduleRetryEffect(workInProgress, retryQueue) { @@ -18129,6 +18162,8 @@ function completeWork(current, workInProgress, renderLanes) { popHostContext(workInProgress); var _type = workInProgress.type; + var _maySuspend = maySuspendCommit(); + if (current !== null && workInProgress.stateNode != null) { updateHostComponent(current, workInProgress, _type, newProps); @@ -18183,7 +18218,17 @@ function completeWork(current, workInProgress, renderLanes) { // will resume rendering as if the work-in-progress completed. So it must // fully complete. - preloadInstanceAndSuspendIfNeeded(workInProgress); + if (_maySuspend) { + preloadInstanceAndSuspendIfNeeded( + workInProgress, + _type, + newProps, + renderLanes + ); + } else { + workInProgress.flags &= ~SuspenseyCommit; + } + return null; } @@ -22559,6 +22604,50 @@ function commitPassiveUnmountEffects(finishedWork) { commitPassiveUnmountOnFiber(finishedWork); resetCurrentFiber(); } +function accumulateSuspenseyCommit(finishedWork) { + accumulateSuspenseyCommitOnFiber(finishedWork); +} + +function recursivelyAccumulateSuspenseyCommit(parentFiber) { + if (parentFiber.subtreeFlags & SuspenseyCommit) { + var child = parentFiber.child; + + while (child !== null) { + accumulateSuspenseyCommitOnFiber(child); + child = child.sibling; + } + } +} + +function accumulateSuspenseyCommitOnFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: { + recursivelyAccumulateSuspenseyCommit(fiber); + + if (fiber.flags & SuspenseyCommit) { + if (fiber.memoizedState !== null) { + suspendResource(); + } + } + + break; + } + + case HostComponent: { + recursivelyAccumulateSuspenseyCommit(fiber); + + break; + } + + case HostRoot: + case HostPortal: + // eslint-disable-next-line-no-fallthrough + + default: { + recursivelyAccumulateSuspenseyCommit(fiber); + } + } +} function detachAlternateSiblings(parentFiber) { // A fiber was deleted from this parent fiber, but it's still part of the @@ -24161,6 +24250,11 @@ function commitRootWhenReady( lanes ) { if (includesOnlyNonUrgentLanes(lanes)) { + // the suspensey resources. The renderer is responsible for accumulating + // all the load events. This all happens in a single synchronous + // transaction, so it track state in its own module scope. + + accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should // suspend. If it's not ready, it will return a callback to subscribe to // a ready event. diff --git a/compiled/facebook-www/ReactART-dev.modern.js b/compiled/facebook-www/ReactART-dev.modern.js index b5f57a28e9d4a..93fef4b092b44 100644 --- a/compiled/facebook-www/ReactART-dev.modern.js +++ b/compiled/facebook-www/ReactART-dev.modern.js @@ -69,7 +69,7 @@ function _assertThisInitialized(self) { return self; } -var ReactVersion = "18.3.0-www-modern-34dd0fe8"; +var ReactVersion = "18.3.0-www-modern-fc6afcc9"; var LegacyRoot = 0; var ConcurrentRoot = 1; @@ -2518,24 +2518,24 @@ function lanesToEventPriority(lanes) { // Renderers that don't support hydration // can re-export everything from this module. -function shim$1() { +function shim$2() { throw new Error( "The current renderer does not support hydration. " + "This error is likely caused by a bug in React. " + "Please file an issue." ); } // Hydration (when unsupported) -var isSuspenseInstancePending = shim$1; -var isSuspenseInstanceFallback = shim$1; -var getSuspenseInstanceFallbackErrorDetails = shim$1; -var registerSuspenseInstanceRetry = shim$1; -var clearSuspenseBoundary = shim$1; -var clearSuspenseBoundaryFromContainer = shim$1; -var errorHydratingContainer = shim$1; +var isSuspenseInstancePending = shim$2; +var isSuspenseInstanceFallback = shim$2; +var getSuspenseInstanceFallbackErrorDetails = shim$2; +var registerSuspenseInstanceRetry = shim$2; +var clearSuspenseBoundary = shim$2; +var clearSuspenseBoundaryFromContainer = shim$2; +var errorHydratingContainer = shim$2; // Renderers that don't support React Scopes // can re-export everything from this module. -function shim() { +function shim$1() { throw new Error( "The current renderer does not support React Scopes. " + "This error is likely caused by a bug in React. " + @@ -2543,8 +2543,19 @@ function shim() { ); } // React Scopes (when unsupported) -var prepareScopeUpdate = shim; -var getInstanceFromScope = shim; +var prepareScopeUpdate = shim$1; +var getInstanceFromScope = shim$1; + +// Renderers that don't support hydration +// can re-export everything from this module. +function shim() { + throw new Error( + "The current renderer does not support Resources. " + + "This error is likely caused by a bug in React. " + + "Please file an issue." + ); +} // Resources (when unsupported) +var suspendResource = shim; var pooledTransform = new Transform(); var NO_CONTEXT = {}; @@ -2920,6 +2931,9 @@ function unhideTextInstance(textInstance, text) { function getInstanceFromNode(node) { throw new Error("Not implemented."); } +function maySuspendCommit(type, props) { + return false; +} function preloadInstance(type, props) { // Return true to indicate it's already loaded return true; @@ -5332,6 +5346,13 @@ function trackUsedThenable(thenableState, thenable, index) { } } } +function suspendCommit() { + // This extra indirection only exists so it can handle passing + // noopSuspenseyCommitThenable through to throwException. + // TODO: Factor the thenable check out of throwException + suspendedThenable = noopSuspenseyCommitThenable; + throw SuspenseyCommitException; +} // This is used to track the actual thenable that suspended so it can be // passed to the rest of the Suspense implementation — which, for historical // reasons, expects to receive a thenable. @@ -17376,16 +17397,28 @@ function preloadInstanceAndSuspendIfNeeded( props, renderLanes ) { - // Ask the renderer if this instance should suspend the commit. - { - // If this flag was set previously, we can remove it. The flag represents - // whether this particular set of props might ever need to suspend. The - // safest thing to do is for maySuspendCommit to always return true, but - // if the renderer is reasonably confident that the underlying resource - // won't be evicted, it can return false as a performance optimization. - workInProgress.flags &= ~SuspenseyCommit; - return; - } // Mark this fiber with a flag. We use this right before the commit phase to + workInProgress.flags |= SuspenseyCommit; // Check if we're rendering at a "non-urgent" priority. This is the same + // check that `useDeferredValue` does to determine whether it needs to + // defer. This is partly for gradual adoption purposes (i.e. shouldn't start + // suspending until you opt in with startTransition or Suspense) but it + // also happens to be the desired behavior for the concrete use cases we've + // thought of so far, like CSS loading, fonts, images, etc. + // TODO: We may decide to expose a way to force a fallback even during a + // sync update. + + if (!includesOnlyNonUrgentLanes(renderLanes)); + else { + // Preload the instance + var isReady = preloadInstance(); + + if (!isReady) { + if (shouldRemainOnPreviousScreen()); + else { + // Trigger a fallback rather than block the render. + suspendCommit(); + } + } + } } function scheduleRetryEffect(workInProgress, retryQueue) { @@ -17811,6 +17844,8 @@ function completeWork(current, workInProgress, renderLanes) { popHostContext(workInProgress); var _type = workInProgress.type; + var _maySuspend = maySuspendCommit(); + if (current !== null && workInProgress.stateNode != null) { updateHostComponent(current, workInProgress, _type, newProps); @@ -17865,7 +17900,17 @@ function completeWork(current, workInProgress, renderLanes) { // will resume rendering as if the work-in-progress completed. So it must // fully complete. - preloadInstanceAndSuspendIfNeeded(workInProgress); + if (_maySuspend) { + preloadInstanceAndSuspendIfNeeded( + workInProgress, + _type, + newProps, + renderLanes + ); + } else { + workInProgress.flags &= ~SuspenseyCommit; + } + return null; } @@ -22219,6 +22264,50 @@ function commitPassiveUnmountEffects(finishedWork) { commitPassiveUnmountOnFiber(finishedWork); resetCurrentFiber(); } +function accumulateSuspenseyCommit(finishedWork) { + accumulateSuspenseyCommitOnFiber(finishedWork); +} + +function recursivelyAccumulateSuspenseyCommit(parentFiber) { + if (parentFiber.subtreeFlags & SuspenseyCommit) { + var child = parentFiber.child; + + while (child !== null) { + accumulateSuspenseyCommitOnFiber(child); + child = child.sibling; + } + } +} + +function accumulateSuspenseyCommitOnFiber(fiber) { + switch (fiber.tag) { + case HostHoistable: { + recursivelyAccumulateSuspenseyCommit(fiber); + + if (fiber.flags & SuspenseyCommit) { + if (fiber.memoizedState !== null) { + suspendResource(); + } + } + + break; + } + + case HostComponent: { + recursivelyAccumulateSuspenseyCommit(fiber); + + break; + } + + case HostRoot: + case HostPortal: + // eslint-disable-next-line-no-fallthrough + + default: { + recursivelyAccumulateSuspenseyCommit(fiber); + } + } +} function detachAlternateSiblings(parentFiber) { // A fiber was deleted from this parent fiber, but it's still part of the @@ -23821,6 +23910,11 @@ function commitRootWhenReady( lanes ) { if (includesOnlyNonUrgentLanes(lanes)) { + // the suspensey resources. The renderer is responsible for accumulating + // all the load events. This all happens in a single synchronous + // transaction, so it track state in its own module scope. + + accumulateSuspenseyCommit(finishedWork); // At the end, ask the renderer if it's ready to commit, or if we should // suspend. If it's not ready, it will return a callback to subscribe to // a ready event. diff --git a/compiled/facebook-www/ReactART-prod.classic.js b/compiled/facebook-www/ReactART-prod.classic.js index 2d7995d2ea04a..a47cddef084f1 100644 --- a/compiled/facebook-www/ReactART-prod.classic.js +++ b/compiled/facebook-www/ReactART-prod.classic.js @@ -642,10 +642,10 @@ function lanesToEventPriority(lanes) { : 8 : 2; } -function shim$1() { +function shim$2() { throw Error(formatProdErrorMessage(305)); } -function shim() { +function shim$1() { throw Error(formatProdErrorMessage(357)); } var pooledTransform = new Transform(), @@ -2290,7 +2290,7 @@ function findFirstSuspended(row) { for (var node = row; null !== node; ) { if (13 === node.tag) { var state = node.memoizedState; - if (null !== state && (null === state.dehydrated || shim$1() || shim$1())) + if (null !== state && (null === state.dehydrated || shim$2() || shim$2())) return node; } else if (19 === node.tag && void 0 !== node.memoizedProps.revealOrder) { if (0 !== (node.flags & 128)) return node; @@ -4517,9 +4517,9 @@ function updateDehydratedSuspenseComponent( renderLanes, null ); - if (shim$1()) + if (shim$2()) return ( - (suspenseState = shim$1().digest), + (suspenseState = shim$2().digest), (nextProps = Error(formatProdErrorMessage(419))), (nextProps.digest = suspenseState), (suspenseState = createCapturedValue(nextProps, suspenseState, void 0)), @@ -4598,12 +4598,12 @@ function updateDehydratedSuspenseComponent( null ); } - if (shim$1()) + if (shim$2()) return ( (workInProgress.flags |= 128), (workInProgress.child = current.child), retryDehydratedSuspenseBoundary.bind(null, current), - shim$1(), + shim$2(), null ); current = mountSuspensePrimaryChildren(workInProgress, nextProps.children); @@ -5271,7 +5271,7 @@ function collectNearestChildContextValues( } } function DO_NOT_USE_queryAllNodes(fn) { - var currentFiber = shim(); + var currentFiber = shim$1(); if (null === currentFiber) return null; currentFiber = currentFiber.child; var scopedNodes = []; @@ -5280,7 +5280,7 @@ function DO_NOT_USE_queryAllNodes(fn) { return 0 === scopedNodes.length ? null : scopedNodes; } function DO_NOT_USE_queryFirstNode(fn) { - var currentFiber = shim(); + var currentFiber = shim$1(); if (null === currentFiber) return null; currentFiber = currentFiber.child; return null !== currentFiber @@ -5291,7 +5291,7 @@ function containsNode() { throw Error(formatProdErrorMessage(248)); } function getChildContextValues(context) { - var currentFiber = shim(); + var currentFiber = shim$1(); if (null === currentFiber) return []; currentFiber = currentFiber.child; var childContextValues = []; @@ -5654,7 +5654,7 @@ function completeWork(current, workInProgress, renderLanes) { containsNode: containsNode, getChildContextValues: getChildContextValues }), - shim(), + shim$1(), null !== workInProgress.ref && ((workInProgress.flags |= 2097664), (workInProgress.flags |= 4))) : (null !== workInProgress.ref && (workInProgress.flags |= 4), @@ -6468,7 +6468,7 @@ function commitDeletionEffectsOnFiber( null !== finishedRoot && (finishedRoot = finishedRoot.onDeleted) && finishedRoot(deletedFiber.stateNode); - null !== hostParent && shim$1(); + null !== hostParent && shim$2(); break; case 4: prevHostParent = hostParent; @@ -6868,7 +6868,7 @@ function commitMutationEffectsOnFiber(finishedWork, root) { flags & 512 && (null !== current && safelyDetachRef(finishedWork, finishedWork.return), safelyAttachRef(finishedWork, finishedWork.return)); - flags & 4 && shim(); + flags & 4 && shim$1(); break; default: recursivelyTraverseMutationEffects(root, finishedWork), @@ -7473,6 +7473,26 @@ function recursivelyTraverseAtomicPassiveEffects( parentFiber = parentFiber.sibling; } } +function recursivelyAccumulateSuspenseyCommit(parentFiber) { + if (parentFiber.subtreeFlags & 16777216) + for (parentFiber = parentFiber.child; null !== parentFiber; ) + accumulateSuspenseyCommitOnFiber(parentFiber), + (parentFiber = parentFiber.sibling); +} +function accumulateSuspenseyCommitOnFiber(fiber) { + switch (fiber.tag) { + case 26: + recursivelyAccumulateSuspenseyCommit(fiber); + if (fiber.flags & 16777216 && null !== fiber.memoizedState) + throw Error(formatProdErrorMessage(442)); + break; + case 5: + recursivelyAccumulateSuspenseyCommit(fiber); + break; + default: + recursivelyAccumulateSuspenseyCommit(fiber); + } +} function detachAlternateSiblings(parentFiber) { var previousFiber = parentFiber.alternate; if ( @@ -7990,7 +8010,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { case 1: throw Error(formatProdErrorMessage(345)); case 2: - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; case 3: markRootSuspended(root, lanes); @@ -8013,7 +8039,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); break; } - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; case 4: markRootSuspended(root, lanes); @@ -8057,10 +8089,22 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); break; } - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; case 5: - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; default: throw Error(formatProdErrorMessage(329)); @@ -8103,7 +8147,14 @@ function queueRecoverableErrors(errors) { errors ); } -function commitRootWhenReady(root) { +function commitRootWhenReady( + root, + finishedWork, + recoverableErrors, + transitions, + lanes +) { + 0 === (lanes & 42) && accumulateSuspenseyCommitOnFiber(finishedWork); commitRoot( root, workInProgressRootRecoverableErrors, @@ -9965,19 +10016,19 @@ var slice = Array.prototype.slice, }; return Text; })(React.Component), - devToolsConfig$jscomp$inline_1168 = { + devToolsConfig$jscomp$inline_1141 = { findFiberByHostInstance: function () { return null; }, bundleType: 0, - version: "18.3.0-www-classic-52e77af5", + version: "18.3.0-www-classic-2dcecc61", rendererPackageName: "react-art" }; -var internals$jscomp$inline_1343 = { - bundleType: devToolsConfig$jscomp$inline_1168.bundleType, - version: devToolsConfig$jscomp$inline_1168.version, - rendererPackageName: devToolsConfig$jscomp$inline_1168.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1168.rendererConfig, +var internals$jscomp$inline_1319 = { + bundleType: devToolsConfig$jscomp$inline_1141.bundleType, + version: devToolsConfig$jscomp$inline_1141.version, + rendererPackageName: devToolsConfig$jscomp$inline_1141.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1141.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9994,26 +10045,26 @@ var internals$jscomp$inline_1343 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1168.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1141.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-www-classic-52e77af5" + reconcilerVersion: "18.3.0-www-classic-2dcecc61" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1344 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1320 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1344.isDisabled && - hook$jscomp$inline_1344.supportsFiber + !hook$jscomp$inline_1320.isDisabled && + hook$jscomp$inline_1320.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1344.inject( - internals$jscomp$inline_1343 + (rendererID = hook$jscomp$inline_1320.inject( + internals$jscomp$inline_1319 )), - (injectedHook = hook$jscomp$inline_1344); + (injectedHook = hook$jscomp$inline_1320); } catch (err) {} } var Path = Mode$1.Path; diff --git a/compiled/facebook-www/ReactART-prod.modern.js b/compiled/facebook-www/ReactART-prod.modern.js index f55057dcd7296..3340a4b2d75a7 100644 --- a/compiled/facebook-www/ReactART-prod.modern.js +++ b/compiled/facebook-www/ReactART-prod.modern.js @@ -526,10 +526,10 @@ function lanesToEventPriority(lanes) { : 8 : 2; } -function shim$1() { +function shim$2() { throw Error(formatProdErrorMessage(305)); } -function shim() { +function shim$1() { throw Error(formatProdErrorMessage(357)); } var pooledTransform = new Transform(), @@ -2096,7 +2096,7 @@ function findFirstSuspended(row) { for (var node = row; null !== node; ) { if (13 === node.tag) { var state = node.memoizedState; - if (null !== state && (null === state.dehydrated || shim$1() || shim$1())) + if (null !== state && (null === state.dehydrated || shim$2() || shim$2())) return node; } else if (19 === node.tag && void 0 !== node.memoizedProps.revealOrder) { if (0 !== (node.flags & 128)) return node; @@ -4272,9 +4272,9 @@ function updateDehydratedSuspenseComponent( renderLanes, null ); - if (shim$1()) + if (shim$2()) return ( - (suspenseState = shim$1().digest), + (suspenseState = shim$2().digest), (nextProps = Error(formatProdErrorMessage(419))), (nextProps.digest = suspenseState), (suspenseState = createCapturedValue(nextProps, suspenseState, void 0)), @@ -4353,12 +4353,12 @@ function updateDehydratedSuspenseComponent( null ); } - if (shim$1()) + if (shim$2()) return ( (workInProgress.flags |= 128), (workInProgress.child = current.child), retryDehydratedSuspenseBoundary.bind(null, current), - shim$1(), + shim$2(), null ); current = mountSuspensePrimaryChildren(workInProgress, nextProps.children); @@ -5022,7 +5022,7 @@ function collectNearestChildContextValues( } } function DO_NOT_USE_queryAllNodes(fn) { - var currentFiber = shim(); + var currentFiber = shim$1(); if (null === currentFiber) return null; currentFiber = currentFiber.child; var scopedNodes = []; @@ -5031,7 +5031,7 @@ function DO_NOT_USE_queryAllNodes(fn) { return 0 === scopedNodes.length ? null : scopedNodes; } function DO_NOT_USE_queryFirstNode(fn) { - var currentFiber = shim(); + var currentFiber = shim$1(); if (null === currentFiber) return null; currentFiber = currentFiber.child; return null !== currentFiber @@ -5042,7 +5042,7 @@ function containsNode() { throw Error(formatProdErrorMessage(248)); } function getChildContextValues(context) { - var currentFiber = shim(); + var currentFiber = shim$1(); if (null === currentFiber) return []; currentFiber = currentFiber.child; var childContextValues = []; @@ -5395,7 +5395,7 @@ function completeWork(current, workInProgress, renderLanes) { containsNode: containsNode, getChildContextValues: getChildContextValues }), - shim(), + shim$1(), null !== workInProgress.ref && ((workInProgress.flags |= 2097664), (workInProgress.flags |= 4))) : (null !== workInProgress.ref && (workInProgress.flags |= 4), @@ -6200,7 +6200,7 @@ function commitDeletionEffectsOnFiber( null !== finishedRoot && (finishedRoot = finishedRoot.onDeleted) && finishedRoot(deletedFiber.stateNode); - null !== hostParent && shim$1(); + null !== hostParent && shim$2(); break; case 4: prevHostParent = hostParent; @@ -6600,7 +6600,7 @@ function commitMutationEffectsOnFiber(finishedWork, root) { flags & 512 && (null !== current && safelyDetachRef(finishedWork, finishedWork.return), safelyAttachRef(finishedWork, finishedWork.return)); - flags & 4 && shim(); + flags & 4 && shim$1(); break; default: recursivelyTraverseMutationEffects(root, finishedWork), @@ -7205,6 +7205,26 @@ function recursivelyTraverseAtomicPassiveEffects( parentFiber = parentFiber.sibling; } } +function recursivelyAccumulateSuspenseyCommit(parentFiber) { + if (parentFiber.subtreeFlags & 16777216) + for (parentFiber = parentFiber.child; null !== parentFiber; ) + accumulateSuspenseyCommitOnFiber(parentFiber), + (parentFiber = parentFiber.sibling); +} +function accumulateSuspenseyCommitOnFiber(fiber) { + switch (fiber.tag) { + case 26: + recursivelyAccumulateSuspenseyCommit(fiber); + if (fiber.flags & 16777216 && null !== fiber.memoizedState) + throw Error(formatProdErrorMessage(442)); + break; + case 5: + recursivelyAccumulateSuspenseyCommit(fiber); + break; + default: + recursivelyAccumulateSuspenseyCommit(fiber); + } +} function detachAlternateSiblings(parentFiber) { var previousFiber = parentFiber.alternate; if ( @@ -7722,7 +7742,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { case 1: throw Error(formatProdErrorMessage(345)); case 2: - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; case 3: markRootSuspended(root, lanes); @@ -7745,7 +7771,13 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); break; } - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; case 4: markRootSuspended(root, lanes); @@ -7789,10 +7821,22 @@ function performConcurrentWorkOnRoot(root, didTimeout) { ); break; } - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; case 5: - commitRootWhenReady(root); + commitRootWhenReady( + root, + didTimeout, + workInProgressRootRecoverableErrors, + workInProgressTransitions, + lanes + ); break; default: throw Error(formatProdErrorMessage(329)); @@ -7835,7 +7879,14 @@ function queueRecoverableErrors(errors) { errors ); } -function commitRootWhenReady(root) { +function commitRootWhenReady( + root, + finishedWork, + recoverableErrors, + transitions, + lanes +) { + 0 === (lanes & 42) && accumulateSuspenseyCommitOnFiber(finishedWork); commitRoot( root, workInProgressRootRecoverableErrors, @@ -9630,19 +9681,19 @@ var slice = Array.prototype.slice, }; return Text; })(React.Component), - devToolsConfig$jscomp$inline_1148 = { + devToolsConfig$jscomp$inline_1121 = { findFiberByHostInstance: function () { return null; }, bundleType: 0, - version: "18.3.0-www-modern-b7692384", + version: "18.3.0-www-modern-ef21bdef", rendererPackageName: "react-art" }; -var internals$jscomp$inline_1323 = { - bundleType: devToolsConfig$jscomp$inline_1148.bundleType, - version: devToolsConfig$jscomp$inline_1148.version, - rendererPackageName: devToolsConfig$jscomp$inline_1148.rendererPackageName, - rendererConfig: devToolsConfig$jscomp$inline_1148.rendererConfig, +var internals$jscomp$inline_1299 = { + bundleType: devToolsConfig$jscomp$inline_1121.bundleType, + version: devToolsConfig$jscomp$inline_1121.version, + rendererPackageName: devToolsConfig$jscomp$inline_1121.rendererPackageName, + rendererConfig: devToolsConfig$jscomp$inline_1121.rendererConfig, overrideHookState: null, overrideHookStateDeletePath: null, overrideHookStateRenamePath: null, @@ -9659,26 +9710,26 @@ var internals$jscomp$inline_1323 = { return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: - devToolsConfig$jscomp$inline_1148.findFiberByHostInstance || + devToolsConfig$jscomp$inline_1121.findFiberByHostInstance || emptyFindFiberByHostInstance, findHostInstancesForRefresh: null, scheduleRefresh: null, scheduleRoot: null, setRefreshHandler: null, getCurrentFiber: null, - reconcilerVersion: "18.3.0-www-modern-b7692384" + reconcilerVersion: "18.3.0-www-modern-ef21bdef" }; if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) { - var hook$jscomp$inline_1324 = __REACT_DEVTOOLS_GLOBAL_HOOK__; + var hook$jscomp$inline_1300 = __REACT_DEVTOOLS_GLOBAL_HOOK__; if ( - !hook$jscomp$inline_1324.isDisabled && - hook$jscomp$inline_1324.supportsFiber + !hook$jscomp$inline_1300.isDisabled && + hook$jscomp$inline_1300.supportsFiber ) try { - (rendererID = hook$jscomp$inline_1324.inject( - internals$jscomp$inline_1323 + (rendererID = hook$jscomp$inline_1300.inject( + internals$jscomp$inline_1299 )), - (injectedHook = hook$jscomp$inline_1324); + (injectedHook = hook$jscomp$inline_1300); } catch (err) {} } var Path = Mode$1.Path; diff --git a/compiled/facebook-www/ReactDOM-dev.classic.js b/compiled/facebook-www/ReactDOM-dev.classic.js index ca244b0c202c6..e9ca774f5fbf7 100644 --- a/compiled/facebook-www/ReactDOM-dev.classic.js +++ b/compiled/facebook-www/ReactDOM-dev.classic.js @@ -1076,8625 +1076,8625 @@ function getEventTarget(nativeEvent) { return target.nodeType === TEXT_NODE ? target.parentNode : target; } -var canUseDOM = !!( - typeof window !== "undefined" && - typeof window.document !== "undefined" && - typeof window.document.createElement !== "undefined" -); +var valueStack = []; +var fiberStack; -// $FlowFixMe[method-unbinding] -var hasOwnProperty = Object.prototype.hasOwnProperty; +{ + fiberStack = []; +} -/* - * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol - * and Temporal.* types. See https://github.com/facebook/react/pull/22064. - * - * The functions in this module will throw an easier-to-understand, - * easier-to-debug exception with a clear errors message message explaining the - * problem. (Instead of a confusing exception thrown inside the implementation - * of the `value` object). - */ -// $FlowFixMe only called in DEV, so void return is not possible. -function typeName(value) { - { - // toStringTag is needed for namespaced types like Temporal.Instant - var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; - var type = - (hasToStringTag && value[Symbol.toStringTag]) || - value.constructor.name || - "Object"; // $FlowFixMe +var index = -1; - return type; +function createCursor(defaultValue) { + return { + current: defaultValue + }; +} + +function pop(cursor, fiber) { + if (index < 0) { + { + error("Unexpected pop."); + } + + return; } -} // $FlowFixMe only called in DEV, so void return is not possible. -function willCoercionThrow(value) { { - try { - testStringCoercion(value); - return false; - } catch (e) { - return true; + if (fiber !== fiberStack[index]) { + error("Unexpected Fiber popped."); } } + + cursor.current = valueStack[index]; + valueStack[index] = null; + + { + fiberStack[index] = null; + } + + index--; } -function testStringCoercion(value) { - // If you ended up here by following an exception call stack, here's what's - // happened: you supplied an object or symbol value to React (as a prop, key, - // DOM attribute, CSS property, string ref, etc.) and when React tried to - // coerce it to a string using `'' + value`, an exception was thrown. - // - // The most common types that will cause this exception are `Symbol` instances - // and Temporal objects like `Temporal.Instant`. But any object that has a - // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this - // exception. (Library authors do this to prevent users from using built-in - // numeric operators like `+` or comparison operators like `>=` because custom - // methods are needed to perform accurate arithmetic or comparison.) - // - // To fix the problem, coerce this object or symbol value to a string before - // passing it to React. The most reliable way is usually `String(value)`. - // - // To find which value is throwing, check the browser or debugger console. - // Before this exception was thrown, there should be `console.error` output - // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the - // problem and how that type was used: key, atrribute, input value prop, etc. - // In most cases, this console output also shows the component and its - // ancestor components where the exception happened. - // - // eslint-disable-next-line react-internal/safe-string-coercion - return "" + value; +function push(cursor, value, fiber) { + index++; + valueStack[index] = cursor.current; + + { + fiberStack[index] = fiber; + } + + cursor.current = value; } -function checkAttributeStringCoercion(value, attributeName) { +var contextStackCursor$1 = createCursor(null); +var contextFiberStackCursor = createCursor(null); +var rootInstanceStackCursor = createCursor(null); + +function requiredContext(c) { { - if (willCoercionThrow(value)) { + if (c === null) { error( - "The provided `%s` attribute is an unsupported type %s." + - " This value must be coerced to a string before before using it here.", - attributeName, - typeName(value) + "Expected host context to exist. This error is likely caused by a bug " + + "in React. Please file an issue." ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } + + return c; } -function checkKeyStringCoercion(value) { - { - if (willCoercionThrow(value)) { - error( - "The provided key is an unsupported type %s." + - " This value must be coerced to a string before before using it here.", - typeName(value) - ); - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) - } +function getCurrentRootHostContainer() { + return rootInstanceStackCursor.current; +} + +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, null, 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 context = requiredContext(contextStackCursor$1.current); + var nextContext = getChildHostContext(context, fiber.type); // 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); } -function checkPropStringCoercion(value, propName) { + +// This module only exists as an ESM wrapper around the external CommonJS +var scheduleCallback$2 = Scheduler.unstable_scheduleCallback; +var cancelCallback$1 = Scheduler.unstable_cancelCallback; +var shouldYield = Scheduler.unstable_shouldYield; +var requestPaint = Scheduler.unstable_requestPaint; +var now$1 = Scheduler.unstable_now; +var getCurrentPriorityLevel = Scheduler.unstable_getCurrentPriorityLevel; +var ImmediatePriority = Scheduler.unstable_ImmediatePriority; +var UserBlockingPriority = Scheduler.unstable_UserBlockingPriority; +var NormalPriority$1 = Scheduler.unstable_NormalPriority; +var LowPriority = Scheduler.unstable_LowPriority; +var IdlePriority = Scheduler.unstable_IdlePriority; // this doesn't actually exist on the scheduler, but it *does* +// on scheduler/unstable_mock, which we'll need for internal testing + +var log$2 = Scheduler.log; +var unstable_setDisableYieldValue = Scheduler.unstable_setDisableYieldValue; + +// Helpers to patch console.logs to avoid logging during side-effect free +// replaying on render function. This currently only patches the object +// lazily which won't cover if the log function was extracted eagerly. +// We could also eagerly patch the method. +var disabledDepth = 0; +var prevLog; +var prevInfo; +var prevWarn; +var prevError; +var prevGroup; +var prevGroupCollapsed; +var prevGroupEnd; + +function disabledLog() {} + +disabledLog.__reactDisabledLog = true; +function disableLogs() { { - if (willCoercionThrow(value)) { - error( - "The provided `%s` prop is an unsupported type %s." + - " This value must be coerced to a string before before using it here.", - propName, - typeName(value) - ); + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + prevLog = console.log; + prevInfo = console.info; + prevWarn = console.warn; + prevError = console.error; + prevGroup = console.group; + prevGroupCollapsed = console.groupCollapsed; + prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + var props = { + configurable: true, + enumerable: true, + value: disabledLog, + writable: true + }; // $FlowFixMe Flow thinks console is immutable. + + Object.defineProperties(console, { + info: props, + log: props, + warn: props, + error: props, + group: props, + groupCollapsed: props, + groupEnd: props + }); + /* eslint-enable react-internal/no-production-logging */ } + + disabledDepth++; } } -function checkCSSPropertyStringCoercion(value, propName) { +function reenableLogs() { { - if (willCoercionThrow(value)) { + disabledDepth--; + + if (disabledDepth === 0) { + /* eslint-disable react-internal/no-production-logging */ + var props = { + configurable: true, + enumerable: true, + writable: true + }; // $FlowFixMe Flow thinks console is immutable. + + Object.defineProperties(console, { + log: assign({}, props, { + value: prevLog + }), + info: assign({}, props, { + value: prevInfo + }), + warn: assign({}, props, { + value: prevWarn + }), + error: assign({}, props, { + value: prevError + }), + group: assign({}, props, { + value: prevGroup + }), + groupCollapsed: assign({}, props, { + value: prevGroupCollapsed + }), + groupEnd: assign({}, props, { + value: prevGroupEnd + }) + }); + /* eslint-enable react-internal/no-production-logging */ + } + + if (disabledDepth < 0) { error( - "The provided `%s` CSS property is an unsupported type %s." + - " This value must be coerced to a string before before using it here.", - propName, - typeName(value) + "disabledDepth fell below zero. " + + "This is a bug in React. Please file an issue." ); - - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } -function checkHtmlStringCoercion(value) { - { - if (willCoercionThrow(value)) { + +var rendererID = null; +var injectedHook = null; +var injectedProfilingHooks = null; +var hasLoggedError = false; +var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined"; +function injectInternals(internals) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined") { + // No DevTools + return false; + } + + var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; + + if (hook.isDisabled) { + // This isn't a real property on the hook, but it can be set to opt out + // of DevTools integration and associated warnings and logs. + // https://github.com/facebook/react/issues/3877 + return true; + } + + if (!hook.supportsFiber) { + { error( - "The provided HTML markup uses a value of unsupported type %s." + - " This value must be coerced to a string before before using it here.", - typeName(value) + "The installed version of React DevTools is too old and will not work " + + "with the current version of React. Please update React DevTools. " + + "https://reactjs.org/link/react-devtools" ); + } // DevTools exists, even though it doesn't support Fiber. - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + return true; + } + + try { + if (enableSchedulingProfiler) { + // Conditionally inject these hooks only if Timeline profiler is supported by this build. + // This gives DevTools a way to feature detect that isn't tied to version number + // (since profiling and timeline are controlled by different feature flags). + internals = assign({}, internals, { + getLaneLabelMap: getLaneLabelMap, + injectProfilingHooks: injectProfilingHooks + }); + } + + rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks. + + injectedHook = hook; + } catch (err) { + // Catch all errors because it is unsafe to throw during initialization. + { + error("React instrumentation encountered an error: %s.", err); } } + + if (hook.checkDCE) { + // This is the real DevTools. + return true; + } else { + // This is likely a hook installed by Fast Refresh runtime. + return false; + } } -function checkFormFieldValueStringCoercion(value) { +function onScheduleRoot(root, children) { { - if (willCoercionThrow(value)) { - error( - "Form field values (value, checked, defaultValue, or defaultChecked props)" + - " must be strings, not %s." + - " This value must be coerced to a string before before using it here.", - typeName(value) - ); + if ( + injectedHook && + typeof injectedHook.onScheduleFiberRoot === "function" + ) { + try { + injectedHook.onScheduleFiberRoot(rendererID, root, children); + } catch (err) { + if (!hasLoggedError) { + hasLoggedError = true; - return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + error("React instrumentation encountered an error: %s", err); + } + } } } } +function onCommitRoot$1(root, eventPriority) { + if (injectedHook && typeof injectedHook.onCommitFiberRoot === "function") { + try { + var didError = (root.current.flags & DidCapture) === DidCapture; -// Attributes that aren't in the filter 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. + if (enableProfilerTimer) { + var schedulerPriority; -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. + switch (eventPriority) { + case DiscreteEventPriority: + schedulerPriority = ImmediatePriority; + break; -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. + case ContinuousEventPriority: + schedulerPriority = UserBlockingPriority; + break; -var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric. -// When falsy, it should be removed. + case DefaultEventPriority: + schedulerPriority = NormalPriority$1; + break; -var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric. -// When falsy, it should be removed. + case IdleEventPriority: + schedulerPriority = IdlePriority; + break; -var POSITIVE_NUMERIC = 6; -/* eslint-disable max-len */ + default: + schedulerPriority = NormalPriority$1; + break; + } -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 */ + injectedHook.onCommitFiberRoot( + rendererID, + root, + schedulerPriority, + didError + ); + } + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; -var ATTRIBUTE_NAME_CHAR = - ATTRIBUTE_NAME_START_CHAR + "\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; -var VALID_ATTRIBUTE_NAME_REGEX = new RegExp( - "^[" + ATTRIBUTE_NAME_START_CHAR + "][" + ATTRIBUTE_NAME_CHAR + "]*$" -); -var illegalAttributeNameCache = {}; -var validatedAttributeNameCache = {}; -function isAttributeNameSafe(attributeName) { - if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { - return true; + error("React instrumentation encountered an error: %s", err); + } + } + } } +} +function onPostCommitRoot(root) { + if ( + injectedHook && + typeof injectedHook.onPostCommitFiberRoot === "function" + ) { + try { + injectedHook.onPostCommitFiberRoot(rendererID, root); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; - if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { - return false; + error("React instrumentation encountered an error: %s", err); + } + } + } } +} +function onCommitUnmount(fiber) { + if (injectedHook && typeof injectedHook.onCommitFiberUnmount === "function") { + try { + injectedHook.onCommitFiberUnmount(rendererID, fiber); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; - if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { - validatedAttributeNameCache[attributeName] = true; - return true; + error("React instrumentation encountered an error: %s", err); + } + } + } } - - illegalAttributeNameCache[attributeName] = true; - +} +function setIsStrictModeForDevtools(newIsStrictMode) { { - error("Invalid attribute name: `%s`", attributeName); - } + if (typeof log$2 === "function") { + // We're in a test because Scheduler.log only exists + // in SchedulerMock. To reduce the noise in strict mode tests, + // suppress warnings and disable scheduler yielding during the double render + unstable_setDisableYieldValue(newIsStrictMode); + setSuppressWarning(newIsStrictMode); + } - return false; -} -function getPropertyInfo(name) { - return properties.hasOwnProperty(name) ? properties[name] : null; -} // $FlowFixMe[missing-this-annot] + if (injectedHook && typeof injectedHook.setStrictMode === "function") { + try { + injectedHook.setStrictMode(rendererID, newIsStrictMode); + } catch (err) { + { + if (!hasLoggedError) { + hasLoggedError = true; -function PropertyInfoRecord( - name, - type, - mustUseProperty, - attributeName, - attributeNamespace, - sanitizeURL, - removeEmptyString -) { - 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; - this.sanitizeURL = sanitizeURL; - this.removeEmptyString = removeEmptyString; -} // When adding attributes to this list, be sure to also add them to -// the `possibleStandardNames` module to ensure casing and incorrect -// name warnings. + error("React instrumentation encountered an error: %s", err); + } + } + } + } + } +} // Profiler API hooks -var properties = {}; // A few React string attributes have a different name. -// This is a mapping from React prop names to the attribute names. +function injectProfilingHooks(profilingHooks) { + injectedProfilingHooks = profilingHooks; +} -[ - ["acceptCharset", "accept-charset"], - ["className", "class"], - ["htmlFor", "for"], - ["httpEquiv", "http-equiv"] -].forEach(function (_ref) { - var name = _ref[0], - attributeName = _ref[1]; - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - STRING, - false, // mustUseProperty - attributeName, // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // 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). +function getLaneLabelMap() { + if (enableSchedulingProfiler) { + var map = new Map(); + var lane = 1; -["contentEditable", "draggable", "spellCheck", "value"].forEach(function ( - name -) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - BOOLEANISH_STRING, - false, // mustUseProperty - name.toLowerCase(), // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // 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. + for (var index = 0; index < TotalLanes; index++) { + var label = getLabelForLane(lane); + map.set(lane, label); + lane *= 2; + } -[ - "autoReverse", - "externalResourcesRequired", - "focusable", - "preserveAlpha" -].forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - BOOLEANISH_STRING, - false, // mustUseProperty - name, // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // These are HTML boolean attributes. + return map; + } else { + return null; + } +} -[ - "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", - "disablePictureInPicture", - "disableRemotePlayback", - "formNoValidate", - "hidden", - "loop", - "noModule", - "noValidate", - "open", - "playsInline", - "readOnly", - "required", - "reversed", - "scoped", - "seamless", // Microdata - "itemScope" -].forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - BOOLEAN, - false, // mustUseProperty - name.toLowerCase(), // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // These are the few React props that we set as DOM properties -// rather than attributes. These are all booleans. +function markCommitStarted(lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markCommitStarted === "function" + ) { + injectedProfilingHooks.markCommitStarted(lanes); + } + } +} +function markCommitStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markCommitStopped === "function" + ) { + injectedProfilingHooks.markCommitStopped(); + } + } +} +function markComponentRenderStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentRenderStarted === "function" + ) { + injectedProfilingHooks.markComponentRenderStarted(fiber); + } + } +} +function markComponentRenderStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentRenderStopped === "function" + ) { + injectedProfilingHooks.markComponentRenderStopped(); + } + } +} +function markComponentPassiveEffectMountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber); + } + } +} +function markComponentPassiveEffectMountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectMountStopped(); + } + } +} +function markComponentPassiveEffectUnmountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber); + } + } +} +function markComponentPassiveEffectUnmountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === + "function" + ) { + injectedProfilingHooks.markComponentPassiveEffectUnmountStopped(); + } + } +} +function markComponentLayoutEffectMountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber); + } + } +} +function markComponentLayoutEffectMountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectMountStopped(); + } + } +} +function markComponentLayoutEffectUnmountStarted(fiber) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber); + } + } +} +function markComponentLayoutEffectUnmountStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === + "function" + ) { + injectedProfilingHooks.markComponentLayoutEffectUnmountStopped(); + } + } +} +function markComponentErrored(fiber, thrownValue, lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentErrored === "function" + ) { + injectedProfilingHooks.markComponentErrored(fiber, thrownValue, lanes); + } + } +} +function markComponentSuspended(fiber, wakeable, lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markComponentSuspended === "function" + ) { + injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes); + } + } +} +function markLayoutEffectsStarted(lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markLayoutEffectsStarted === "function" + ) { + injectedProfilingHooks.markLayoutEffectsStarted(lanes); + } + } +} +function markLayoutEffectsStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markLayoutEffectsStopped === "function" + ) { + injectedProfilingHooks.markLayoutEffectsStopped(); + } + } +} +function markPassiveEffectsStarted(lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markPassiveEffectsStarted === "function" + ) { + injectedProfilingHooks.markPassiveEffectsStarted(lanes); + } + } +} +function markPassiveEffectsStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markPassiveEffectsStopped === "function" + ) { + injectedProfilingHooks.markPassiveEffectsStopped(); + } + } +} +function markRenderStarted(lanes) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderStarted === "function" + ) { + injectedProfilingHooks.markRenderStarted(lanes); + } + } +} +function markRenderYielded() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderYielded === "function" + ) { + injectedProfilingHooks.markRenderYielded(); + } + } +} +function markRenderStopped() { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderStopped === "function" + ) { + injectedProfilingHooks.markRenderStopped(); + } + } +} +function markRenderScheduled(lane) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markRenderScheduled === "function" + ) { + injectedProfilingHooks.markRenderScheduled(lane); + } + } +} +function markForceUpdateScheduled(fiber, lane) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markForceUpdateScheduled === "function" + ) { + injectedProfilingHooks.markForceUpdateScheduled(fiber, lane); + } + } +} +function markStateUpdateScheduled(fiber, lane) { + if (enableSchedulingProfiler) { + if ( + injectedProfilingHooks !== null && + typeof injectedProfilingHooks.markStateUpdateScheduled === "function" + ) { + injectedProfilingHooks.markStateUpdateScheduled(fiber, lane); + } + } +} -[ - "checked", // Note: `option.selected` is not updated if `select.multiple` is - // disabled with `removeAttribute`. We have special logic for handling this. - "multiple", - "muted", - "selected" // NOTE: if you add a camelCased prop to this list, - // you'll need to set attributeName to name.toLowerCase() - // instead in the assignment below. -].forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - BOOLEAN, - true, // mustUseProperty - name, // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // These are HTML attributes that are "overloaded booleans": they behave like -// booleans, but can also accept a string value. +var NoMode = + /* */ + 0; // TODO: Remove ConcurrentMode by reading from the root tag instead -[ - "capture", - "download" // NOTE: if you add a camelCased prop to this list, - // you'll need to set attributeName to name.toLowerCase() - // instead in the assignment below. -].forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - OVERLOADED_BOOLEAN, - false, // mustUseProperty - name, // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // These are HTML attributes that must be positive numbers. +var ConcurrentMode = + /* */ + 1; +var ProfileMode = + /* */ + 2; +var DebugTracingMode = + /* */ + 4; +var StrictLegacyMode = + /* */ + 8; +var StrictEffectsMode = + /* */ + 16; +var ConcurrentUpdatesByDefaultMode = + /* */ + 32; -[ - "cols", - "rows", - "size", - "span" // NOTE: if you add a camelCased prop to this list, - // you'll need to set attributeName to name.toLowerCase() - // instead in the assignment below. -].forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - POSITIVE_NUMERIC, - false, // mustUseProperty - name, // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // These are HTML attributes that must be numbers. +// TODO: This is pretty well supported by browsers. Maybe we can drop it. +var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros. +// Based on: +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 -["rowSpan", "start"].forEach(function (name) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[name] = new PropertyInfoRecord( - name, - NUMERIC, - false, // mustUseProperty - name.toLowerCase(), // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); -var CAMELIZE = /[\-\:]([a-z])/g; +var log$1 = Math.log; +var LN2 = Math.LN2; -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 attribute filter. -// Some of these attributes can be hard to find. This list was created by -// scraping the MDN documentation. +function clz32Fallback(x) { + var asUint = x >>> 0; -[ - "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", - "transform-origin", - "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" // NOTE: if you add a camelCased prop to this list, - // you'll need to set attributeName to name.toLowerCase() - // instead in the assignment below. -].forEach(function (attributeName) { - var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + if (asUint === 0) { + return 32; + } - properties[name] = new PropertyInfoRecord( - name, - STRING, - false, // mustUseProperty - attributeName, - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // String SVG attributes with the xlink namespace. + return (31 - ((log$1(asUint) / LN2) | 0)) | 0; +} -[ - "xlink:actuate", - "xlink:arcrole", - "xlink:role", - "xlink:show", - "xlink:title", - "xlink:type" // NOTE: if you add a camelCased prop to this list, - // you'll need to set attributeName to name.toLowerCase() - // instead in the assignment below. -].forEach(function (attributeName) { - var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions +// If those values are changed that package should be rebuilt and redeployed. - properties[name] = new PropertyInfoRecord( - name, - STRING, - false, // mustUseProperty - attributeName, - "http://www.w3.org/1999/xlink", - false, // sanitizeURL - false - ); -}); // String SVG attributes with the xml namespace. +var TotalLanes = 31; +var NoLanes = + /* */ + 0; +var NoLane = + /* */ + 0; +var SyncHydrationLane = + /* */ + 1; +var SyncLane = + /* */ + 2; +var InputContinuousHydrationLane = + /* */ + 4; +var InputContinuousLane = + /* */ + 8; +var DefaultHydrationLane = + /* */ + 16; +var DefaultLane = + /* */ + 32; +var SyncUpdateLanes = + /* */ + 42; +var TransitionHydrationLane = + /* */ + 64; +var TransitionLanes = + /* */ + 8388480; +var TransitionLane1 = + /* */ + 128; +var TransitionLane2 = + /* */ + 256; +var TransitionLane3 = + /* */ + 512; +var TransitionLane4 = + /* */ + 1024; +var TransitionLane5 = + /* */ + 2048; +var TransitionLane6 = + /* */ + 4096; +var TransitionLane7 = + /* */ + 8192; +var TransitionLane8 = + /* */ + 16384; +var TransitionLane9 = + /* */ + 32768; +var TransitionLane10 = + /* */ + 65536; +var TransitionLane11 = + /* */ + 131072; +var TransitionLane12 = + /* */ + 262144; +var TransitionLane13 = + /* */ + 524288; +var TransitionLane14 = + /* */ + 1048576; +var TransitionLane15 = + /* */ + 2097152; +var TransitionLane16 = + /* */ + 4194304; +var RetryLanes = + /* */ + 125829120; +var RetryLane1 = + /* */ + 8388608; +var RetryLane2 = + /* */ + 16777216; +var RetryLane3 = + /* */ + 33554432; +var RetryLane4 = + /* */ + 67108864; +var SomeRetryLane = RetryLane1; +var SelectiveHydrationLane = + /* */ + 134217728; +var NonIdleLanes = + /* */ + 268435455; +var IdleHydrationLane = + /* */ + 268435456; +var IdleLane = + /* */ + 536870912; +var OffscreenLane = + /* */ + 1073741824; // This function is used for the experimental timeline (react-devtools-timeline) +// It should be kept in sync with the Lanes values above. -[ - "xml:base", - "xml:lang", - "xml:space" // NOTE: if you add a camelCased prop to this list, - // you'll need to set attributeName to name.toLowerCase() - // instead in the assignment below. -].forEach(function (attributeName) { - var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions +function getLabelForLane(lane) { + if (enableSchedulingProfiler) { + if (lane & SyncHydrationLane) { + return "SyncHydrationLane"; + } - properties[name] = new PropertyInfoRecord( - name, - STRING, - false, // mustUseProperty - attributeName, - "http://www.w3.org/XML/1998/namespace", - false, // sanitizeURL - false - ); -}); // 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. + if (lane & SyncLane) { + return "Sync"; + } -["tabIndex", "crossOrigin"].forEach(function (attributeName) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[attributeName] = new PropertyInfoRecord( - attributeName, - STRING, - false, // mustUseProperty - attributeName.toLowerCase(), // attributeName - null, // attributeNamespace - false, // sanitizeURL - false - ); -}); // These attributes accept URLs. These must not allow javascript: URLS. -// These will also need to accept Trusted Types object in the future. + if (lane & InputContinuousHydrationLane) { + return "InputContinuousHydration"; + } -var xlinkHref = "xlinkHref"; // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + if (lane & InputContinuousLane) { + return "InputContinuous"; + } -properties[xlinkHref] = new PropertyInfoRecord( - "xlinkHref", - STRING, - false, // mustUseProperty - "xlink:href", - "http://www.w3.org/1999/xlink", - true, // sanitizeURL - false -); -var formAction = "formAction"; // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + if (lane & DefaultHydrationLane) { + return "DefaultHydration"; + } -properties[formAction] = new PropertyInfoRecord( - "formAction", - STRING, - false, // mustUseProperty - "formaction", // attributeName - null, // attributeNamespace - true, // sanitizeURL - false -); -["src", "href", "action"].forEach(function (attributeName) { - // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - properties[attributeName] = new PropertyInfoRecord( - attributeName, - STRING, - false, // mustUseProperty - attributeName.toLowerCase(), // attributeName - null, // attributeNamespace - true, // sanitizeURL - true - ); -}); + if (lane & DefaultLane) { + return "Default"; + } -// and any newline or tab are filtered out as if they're not part of the URL. -// https://url.spec.whatwg.org/#url-parsing -// Tab or newline are defined as \r\n\t: -// https://infra.spec.whatwg.org/#ascii-tab-or-newline -// A C0 control is a code point in the range \u0000 NULL to \u001F -// INFORMATION SEPARATOR ONE, inclusive: -// https://infra.spec.whatwg.org/#c0-control-or-space + if (lane & TransitionHydrationLane) { + return "TransitionHydration"; + } -/* eslint-disable max-len */ + if (lane & TransitionLanes) { + return "Transition"; + } -var isJavaScriptProtocol = - /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i; + if (lane & RetryLanes) { + return "Retry"; + } -function sanitizeURL(url) { - { - if (isJavaScriptProtocol.test(url)) { - throw new Error( - "React has blocked a javascript: URL as a security precaution." - ); + if (lane & SelectiveHydrationLane) { + return "SelectiveHydration"; + } + + if (lane & IdleHydrationLane) { + return "IdleHydration"; + } + + if (lane & IdleLane) { + return "Idle"; + } + + if (lane & OffscreenLane) { + return "Offscreen"; } } } +var NoTimestamp = -1; +var nextTransitionLane = TransitionLane1; +var nextRetryLane = RetryLane1; -/** - * 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. - */ +function getHighestPriorityLanes(lanes) { + if (enableUnifiedSyncLane) { + var pendingSyncLanes = lanes & SyncUpdateLanes; -function getValueForProperty(node, name, expected, propertyInfo) { - { - if (propertyInfo.mustUseProperty) { - var propertyName = propertyInfo.propertyName; - return node[propertyName]; + if (pendingSyncLanes !== 0) { + return pendingSyncLanes; } + } - var attributeName = propertyInfo.attributeName; + switch (getHighestPriorityLane(lanes)) { + case SyncHydrationLane: + return SyncHydrationLane; - if (!node.hasAttribute(attributeName)) { - // shouldRemoveAttribute - switch (typeof expected) { - case "function": - case "symbol": - // eslint-disable-line - return expected; + case SyncLane: + return SyncLane; - case "boolean": { - if (!propertyInfo.acceptsBooleans) { - return expected; - } - } - } + case InputContinuousHydrationLane: + return InputContinuousHydrationLane; - switch (propertyInfo.type) { - case BOOLEAN: { - if (!expected) { - return expected; - } + case InputContinuousLane: + return InputContinuousLane; - break; - } + case DefaultHydrationLane: + return DefaultHydrationLane; - case OVERLOADED_BOOLEAN: { - if (expected === false) { - return expected; - } + case DefaultLane: + return DefaultLane; - break; - } + case TransitionHydrationLane: + return TransitionHydrationLane; - case NUMERIC: { - if (isNaN(expected)) { - return expected; - } + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case TransitionLane16: + return lanes & TransitionLanes; - break; - } + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + return lanes & RetryLanes; - case POSITIVE_NUMERIC: { - if (isNaN(expected) || expected < 1) { - return expected; - } + case SelectiveHydrationLane: + return SelectiveHydrationLane; - break; - } - } + case IdleHydrationLane: + return IdleHydrationLane; + + case IdleLane: + return IdleLane; + + case OffscreenLane: + return OffscreenLane; + default: { - if (propertyInfo.removeEmptyString && expected === "") { - { - if (name === "src") { - error( - 'An empty string ("") was passed to the %s attribute. ' + - "This may cause the browser to download the whole page again over the network. " + - "To fix this, either do not render the element at all " + - "or pass null to %s instead of an empty string.", - name, - name - ); - } else { - error( - 'An empty string ("") was passed to the %s attribute. ' + - "To fix this, either do not render the element at all " + - "or pass null to %s instead of an empty string.", - name, - name - ); - } - } + error("Should have found matching lanes. This is a bug in React."); + } // This shouldn't be reachable, but as a fallback, return the entire bitmask. - return expected; - } - } + return lanes; + } +} - return expected === undefined ? undefined : null; - } // Even if this property uses a namespace we use getAttribute - // because we assume its namespaced name is the same as our config. - // To use getAttributeNS we need the local name which we don't have - // in our config atm. +function getNextLanes(root, wipLanes) { + // Early bailout if there's no pending work left. + var pendingLanes = root.pendingLanes; - var value = node.getAttribute(attributeName); + if (pendingLanes === NoLanes) { + return NoLanes; + } - if (expected == null) { - // We had an attribute but shouldn't have had one, so read it - // for the error message. - return value; - } // shouldRemoveAttribute + var nextLanes = NoLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished, + // even if the work is suspended. - switch (propertyInfo.type) { - case BOOLEAN: { - if (expected) { - // If this was a boolean, it doesn't matter what the value is - // the fact that we have it is the same as the expected. - // As long as it's positive. - return expected; - } + var nonIdlePendingLanes = pendingLanes & NonIdleLanes; - return value; - } - - case OVERLOADED_BOOLEAN: { - if (value === "") { - return true; - } - - if (expected === false) { - // We had an attribute but shouldn't have had one, so read it - // for the error message. - return value; - } - - break; - } - - case NUMERIC: { - if (isNaN(expected)) { - // We had an attribute but shouldn't have had one, so read it - // for the error message. - return value; - } - - break; - } + if (nonIdlePendingLanes !== NoLanes) { + var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes; - case POSITIVE_NUMERIC: { - if (isNaN(expected) || expected < 1) { - // We had an attribute but shouldn't have had one, so read it - // for the error message. - return value; - } + if (nonIdleUnblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes); + } else { + var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes; - break; + if (nonIdlePingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(nonIdlePingedLanes); } } + } else { + // The only remaining work is Idle. + var unblockedLanes = pendingLanes & ~suspendedLanes; - { - checkAttributeStringCoercion(expected, name); + if (unblockedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(unblockedLanes); + } else { + if (pingedLanes !== NoLanes) { + nextLanes = getHighestPriorityLanes(pingedLanes); + } } + } - if (value === "" + expected) { - return expected; - } + if (nextLanes === NoLanes) { + // This should only be reachable if we're suspended + // TODO: Consider warning in this path if a fallback timer is not scheduled. + return NoLanes; + } // If we're already in the middle of a render, switching lanes will interrupt + // it and we'll lose our progress. We should only do this if the new lanes are + // higher priority. - return value; - } -} -/** - * 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. - */ + if ( + wipLanes !== NoLanes && + wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't + // bother waiting until the root is complete. + (wipLanes & suspendedLanes) === NoLanes + ) { + var nextLane = getHighestPriorityLane(nextLanes); + var wipLane = getHighestPriorityLane(wipLanes); -function getValueForAttribute(node, name, expected) { - { - if (!isAttributeNameSafe(name)) { - return; + if ( + // Tests whether the next lane is equal or lower priority than the wip + // one. This works because the bits decrease in priority as you go left. + nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The + // only difference between default updates and transition updates is that + // default updates do not support refresh transitions. + (nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) + ) { + // Keep working on the existing in-progress tree. Do not interrupt. + return wipLanes; } + } - if (!node.hasAttribute(name)) { - // shouldRemoveAttribute - switch (typeof expected) { - case "function": - case "symbol": - // eslint-disable-line - return expected; + if ((root.current.mode & ConcurrentUpdatesByDefaultMode) !== NoMode); + else if ((nextLanes & InputContinuousLane) !== NoLanes) { + // When updates are sync by default, we entangle continuous priority updates + // and default updates, so they render in the same batch. The only reason + // they use separate lanes is because continuous updates should interrupt + // transitions, but default updates should not. + nextLanes |= pendingLanes & DefaultLane; + } // Check for entangled lanes and add them to the batch. + // + // A lane is said to be entangled with another when it's not allowed to render + // in a batch that does not also include the other lane. Typically we do this + // when multiple updates have the same source, and we only want to respond to + // the most recent event from that source. + // + // Note that we apply entanglements *after* checking for partial work above. + // This means that if a lane is entangled during an interleaved event while + // it's already rendering, we won't interrupt it. This is intentional, since + // entanglement is usually "best effort": we'll try our best to render the + // lanes in the same batch, but it's not worth throwing out partially + // completed work in order to do it. + // TODO: Reconsider this. The counter-argument is that the partial work + // represents an intermediate state, which we don't want to show to the user. + // And by spending extra time finishing it, we're increasing the amount of + // time it takes to show the final state, which is what they are actually + // waiting for. + // + // For those exceptions where entanglement is semantically important, like + // useMutableSource, we should ensure that there is no partial work at the + // time we apply the entanglement. - case "boolean": { - var prefix = name.toLowerCase().slice(0, 5); + var entangledLanes = root.entangledLanes; - if (prefix !== "data-" && prefix !== "aria-") { - return expected; - } - } - } + if (entangledLanes !== NoLanes) { + var entanglements = root.entanglements; + var lanes = nextLanes & entangledLanes; - return expected === undefined ? undefined : null; + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + nextLanes |= entanglements[index]; + lanes &= ~lane; } + } - var value = node.getAttribute(name); + return nextLanes; +} +function getMostRecentEventTime(root, lanes) { + var eventTimes = root.eventTimes; + var mostRecentEventTime = NoTimestamp; - { - checkAttributeStringCoercion(expected, name); - } + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + var eventTime = eventTimes[index]; - if (value === "" + expected) { - return expected; + if (eventTime > mostRecentEventTime) { + mostRecentEventTime = eventTime; } - return value; + lanes &= ~lane; } -} -function getValueForAttributeOnCustomComponent(node, name, expected) { - { - if (!isAttributeNameSafe(name)) { - return; - } - - if (!node.hasAttribute(name)) { - // shouldRemoveAttribute - switch (typeof expected) { - case "symbol": - case "object": - // Symbols and objects are ignored when they're emitted so - // it would be expected that they end up not having an attribute. - return expected; - - case "function": - if (enableCustomElementPropertySupport) { - return expected; - } - break; + return mostRecentEventTime; +} - case "boolean": - if (enableCustomElementPropertySupport) { - if (expected === false) { - return expected; - } - } - } +function computeExpirationTime(lane, currentTime) { + switch (lane) { + case SyncHydrationLane: + case SyncLane: + case InputContinuousHydrationLane: + case InputContinuousLane: + // User interactions should expire slightly more quickly. + // + // NOTE: This is set to the corresponding constant as in Scheduler.js. + // When we made it larger, a product metric in www regressed, suggesting + // there's a user interaction that's being starved by a series of + // synchronous updates. If that theory is correct, the proper solution is + // to fix the starvation. However, this scenario supports the idea that + // expiration times are an important safeguard when starvation + // does happen. + return currentTime + 250; - return expected === undefined ? undefined : null; - } + case DefaultHydrationLane: + case DefaultLane: + case TransitionHydrationLane: + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case TransitionLane16: + return currentTime + 5000; - if (enableCustomElementPropertySupport && name === "className") { - // className is a special cased property on the server to render as an attribute. - name = "class"; - } + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + // TODO: Retries should be allowed to expire if they are CPU bound for + // too long, but when I made this change it caused a spike in browser + // crashes. There must be some other underlying bug; not super urgent but + // ideally should figure out why and fix it. Unfortunately we don't have + // a repro for the crashes, only detected via production metrics. + return NoTimestamp; - var value = node.getAttribute(name); + case SelectiveHydrationLane: + case IdleHydrationLane: + case IdleLane: + case OffscreenLane: + // Anything idle priority or lower should never expire. + return NoTimestamp; - if (enableCustomElementPropertySupport) { - if (value === "" && expected === true) { - return true; + default: + { + error("Should have found matching lanes. This is a bug in React."); } - } - - { - checkAttributeStringCoercion(expected, name); - } - - if (value === "" + expected) { - return expected; - } - return value; + return NoTimestamp; } } -/** - * Sets the value for a property on a node. - * - * @param {DOMElement} node - * @param {string} name - * @param {*} value - */ - -function setValueForProperty(node, name, value) { - if ( - // shouldIgnoreAttribute - // We have already filtered out reserved words. - name.length > 2 && - (name[0] === "o" || name[0] === "O") && - (name[1] === "n" || name[1] === "N") - ) { - return; - } - - var propertyInfo = getPropertyInfo(name); - - if (propertyInfo !== null) { - if (propertyInfo.mustUseProperty) { - // We assume mustUseProperty are of BOOLEAN type because that's the only way we use it - // right now. - node[propertyInfo.propertyName] = - value && typeof value !== "function" && typeof value !== "symbol"; - return; - } // The rest are treated as attributes with special cases. - var attributeName = propertyInfo.attributeName; +function markStarvedLanesAsExpired(root, currentTime) { + // TODO: This gets called every time we yield. We can optimize by storing + // the earliest expiration time on the root. Then use that to quickly bail out + // of this function. + var pendingLanes = root.pendingLanes; + var suspendedLanes = root.suspendedLanes; + var pingedLanes = root.pingedLanes; + var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their + // expiration time. If so, we'll assume the update is being starved and mark + // it as expired to force it to finish. + // + // We exclude retry lanes because those must always be time sliced, in order + // to unwrap uncached promises. + // TODO: Write a test for this - if (value === null) { - node.removeAttribute(attributeName); - return; - } // shouldRemoveAttribute + var lanes = pendingLanes & ~RetryLanes; - switch (typeof value) { - case "undefined": - case "function": - case "symbol": - // eslint-disable-line - node.removeAttribute(attributeName); - return; + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + var expirationTime = expirationTimes[index]; - case "boolean": { - if (!propertyInfo.acceptsBooleans) { - node.removeAttribute(attributeName); - return; - } + if (expirationTime === NoTimestamp) { + // Found a pending lane with no expiration time. If it's not suspended, or + // if it's pinged, assume it's CPU-bound. Compute a new expiration time + // using the current time. + if ( + (lane & suspendedLanes) === NoLanes || + (lane & pingedLanes) !== NoLanes + ) { + // Assumes timestamps are monotonically increasing. + expirationTimes[index] = computeExpirationTime(lane, currentTime); } + } else if (expirationTime <= currentTime) { + // This lane expired + root.expiredLanes |= lane; } - { - if (propertyInfo.removeEmptyString && value === "") { - { - if (name === "src") { - error( - 'An empty string ("") was passed to the %s attribute. ' + - "This may cause the browser to download the whole page again over the network. " + - "To fix this, either do not render the element at all " + - "or pass null to %s instead of an empty string.", - name, - name - ); - } else { - error( - 'An empty string ("") was passed to the %s attribute. ' + - "To fix this, either do not render the element at all " + - "or pass null to %s instead of an empty string.", - name, - name - ); - } - } + lanes &= ~lane; + } +} // This returns the highest priority pending lanes regardless of whether they +// are suspended. - node.removeAttribute(attributeName); - return; - } - } +function getHighestPriorityPendingLanes(root) { + return getHighestPriorityLanes(root.pendingLanes); +} +function getLanesToRetrySynchronouslyOnError(root, originallyAttemptedLanes) { + if (root.errorRecoveryDisabledLanes & originallyAttemptedLanes) { + // The error recovery mechanism is disabled until these lanes are cleared. + return NoLanes; + } - switch (propertyInfo.type) { - case BOOLEAN: - if (value) { - node.setAttribute(attributeName, ""); - } else { - node.removeAttribute(attributeName); - return; - } + var everythingButOffscreen = root.pendingLanes & ~OffscreenLane; - break; + if (everythingButOffscreen !== NoLanes) { + return everythingButOffscreen; + } - case OVERLOADED_BOOLEAN: - if (value === true) { - node.setAttribute(attributeName, ""); - } else if (value === false) { - node.removeAttribute(attributeName); - } else { - { - checkAttributeStringCoercion(value, attributeName); - } + if (everythingButOffscreen & OffscreenLane) { + return OffscreenLane; + } - node.setAttribute(attributeName, value); - } + return NoLanes; +} +function includesSyncLane(lanes) { + return (lanes & (SyncLane | SyncHydrationLane)) !== NoLanes; +} +function includesNonIdleWork(lanes) { + return (lanes & NonIdleLanes) !== NoLanes; +} +function includesOnlyRetries(lanes) { + return (lanes & RetryLanes) === lanes; +} +function includesOnlyNonUrgentLanes(lanes) { + // TODO: Should hydration lanes be included here? This function is only + // used in `updateDeferredValueImpl`. + var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane; + return (lanes & UrgentLanes) === NoLanes; +} +function includesOnlyTransitions(lanes) { + return (lanes & TransitionLanes) === lanes; +} +function includesBlockingLane(root, lanes) { + if ((root.current.mode & ConcurrentUpdatesByDefaultMode) !== NoMode) { + // Concurrent updates by default always use time slicing. + return false; + } - return; + var SyncDefaultLanes = + InputContinuousHydrationLane | + InputContinuousLane | + DefaultHydrationLane | + DefaultLane; + return (lanes & SyncDefaultLanes) !== NoLanes; +} +function includesExpiredLane(root, lanes) { + // This is a separate check from includesBlockingLane because a lane can + // expire after a render has already started. + return (lanes & root.expiredLanes) !== NoLanes; +} +function isTransitionLane(lane) { + return (lane & TransitionLanes) !== NoLanes; +} +function claimNextTransitionLane() { + // Cycle through the lanes, assigning each new transition to the next lane. + // In most cases, this means every transition gets its own lane, until we + // run out of lanes and cycle back to the beginning. + var lane = nextTransitionLane; + nextTransitionLane <<= 1; - case NUMERIC: - if (!isNaN(value)) { - { - checkAttributeStringCoercion(value, attributeName); - } + if ((nextTransitionLane & TransitionLanes) === NoLanes) { + nextTransitionLane = TransitionLane1; + } - node.setAttribute(attributeName, value); - } else { - node.removeAttribute(attributeName); - } + return lane; +} +function claimNextRetryLane() { + var lane = nextRetryLane; + nextRetryLane <<= 1; - break; + if ((nextRetryLane & RetryLanes) === NoLanes) { + nextRetryLane = RetryLane1; + } - case POSITIVE_NUMERIC: - if (!isNaN(value) && value >= 1) { - { - checkAttributeStringCoercion(value, attributeName); - } + return lane; +} +function getHighestPriorityLane(lanes) { + return lanes & -lanes; +} +function pickArbitraryLane(lanes) { + // This wrapper function gets inlined. Only exists so to communicate that it + // doesn't matter which bit is selected; you can pick any bit without + // affecting the algorithms where its used. Here I'm using + // getHighestPriorityLane because it requires the fewest operations. + return getHighestPriorityLane(lanes); +} - node.setAttribute(attributeName, value); - } else { - node.removeAttribute(attributeName); - } +function pickArbitraryLaneIndex(lanes) { + return 31 - clz32(lanes); +} - break; +function laneToIndex(lane) { + return pickArbitraryLaneIndex(lane); +} - default: { - var attributeValue; // `setAttribute` with objects becomes only `[object]` in IE8/9, - // ('' + value) makes it output the correct toString()-value. +function includesSomeLane(a, b) { + return (a & b) !== NoLanes; +} +function isSubsetOfLanes(set, subset) { + return (set & subset) === subset; +} +function mergeLanes(a, b) { + return a | b; +} +function removeLanes(set, subset) { + return set & ~subset; +} +function intersectLanes(a, b) { + return a & b; +} // Seems redundant, but it changes the type from a single lane (used for +// updates) to a group of lanes (used for flushing work). - if (enableTrustedTypesIntegration) { - attributeValue = value; - } else { - { - checkAttributeStringCoercion(value, attributeName); - } +function laneToLanes(lane) { + return lane; +} +function higherPriorityLane(a, b) { + // This works because the bit ranges decrease in priority as you go left. + return a !== NoLane && a < b ? a : b; +} +function createLaneMap(initial) { + // Intentionally pushing one by one. + // https://v8.dev/blog/elements-kinds#avoid-creating-holes + var laneMap = []; - attributeValue = "" + value; - } + for (var i = 0; i < TotalLanes; i++) { + laneMap.push(initial); + } - if (propertyInfo.sanitizeURL) { - sanitizeURL(attributeValue.toString()); - } + return laneMap; +} +function markRootUpdated(root, updateLane, eventTime) { + root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update + // could unblock them. Clear the suspended lanes so that we can try rendering + // them again. + // + // TODO: We really only need to unsuspend only lanes that are in the + // `subtreeLanes` of the updated fiber, or the update lanes of the return + // path. This would exclude suspended updates in an unrelated sibling tree, + // since there's no way for this update to unblock it. + // + // We don't do this if the incoming update is idle, because we never process + // idle updates until after all the regular updates have finished; there's no + // way it could unblock a transition. - var attributeNamespace = propertyInfo.attributeNamespace; + if (updateLane !== IdleLane) { + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + } - if (attributeNamespace) { - node.setAttributeNS( - attributeNamespace, - attributeName, - attributeValue - ); - } else { - node.setAttribute(attributeName, attributeValue); - } - } - } - } else if (isAttributeNameSafe(name)) { - // If the prop isn't in the special list, treat it as a simple attribute. - // shouldRemoveAttribute - if (value === null) { - node.removeAttribute(name); - return; - } + var eventTimes = root.eventTimes; + var index = laneToIndex(updateLane); // We can always overwrite an existing timestamp because we prefer the most + // recent event, and we assume time is monotonically increasing. - switch (typeof value) { - case "undefined": - case "function": - case "symbol": - // eslint-disable-line - node.removeAttribute(name); - return; + eventTimes[index] = eventTime; +} +function markRootSuspended$1(root, suspendedLanes) { + root.suspendedLanes |= suspendedLanes; + root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times. - case "boolean": { - var prefix = name.toLowerCase().slice(0, 5); + var expirationTimes = root.expirationTimes; + var lanes = suspendedLanes; - if (prefix !== "data-" && prefix !== "aria-") { - node.removeAttribute(name); - return; + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + expirationTimes[index] = NoTimestamp; + lanes &= ~lane; + } +} +function markRootPinged(root, pingedLanes) { + root.pingedLanes |= root.suspendedLanes & pingedLanes; +} +function markRootMutableRead(root, updateLane) { + root.mutableReadLanes |= updateLane & root.pendingLanes; +} +function markRootFinished(root, remainingLanes) { + var noLongerPendingLanes = root.pendingLanes & ~remainingLanes; + root.pendingLanes = remainingLanes; // Let's try everything again + + root.suspendedLanes = NoLanes; + root.pingedLanes = NoLanes; + root.expiredLanes &= remainingLanes; + root.mutableReadLanes &= remainingLanes; + root.entangledLanes &= remainingLanes; + root.errorRecoveryDisabledLanes &= remainingLanes; + var entanglements = root.entanglements; + var eventTimes = root.eventTimes; + var expirationTimes = root.expirationTimes; + var hiddenUpdates = root.hiddenUpdates; // Clear the lanes that no longer have pending work + + var lanes = noLongerPendingLanes; + + while (lanes > 0) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; + entanglements[index] = NoLanes; + eventTimes[index] = NoTimestamp; + expirationTimes[index] = NoTimestamp; + var hiddenUpdatesForLane = hiddenUpdates[index]; + + if (hiddenUpdatesForLane !== null) { + hiddenUpdates[index] = null; // "Hidden" updates are updates that were made to a hidden component. They + // have special logic associated with them because they may be entangled + // with updates that occur outside that tree. But once the outer tree + // commits, they behave like regular updates. + + for (var i = 0; i < hiddenUpdatesForLane.length; i++) { + var update = hiddenUpdatesForLane[i]; + + if (update !== null) { + update.lane &= ~OffscreenLane; } } } - { - checkAttributeStringCoercion(value, name); - } - - node.setAttribute(name, enableTrustedTypesIntegration ? value : "" + value); + lanes &= ~lane; } } -function setValueForPropertyOnCustomComponent(node, name, value) { - if ( - enableCustomElementPropertySupport && - name[0] === "o" && - name[1] === "n" - ) { - var useCapture = name.endsWith("Capture"); - var eventName = name.substr(2, useCapture ? name.length - 9 : undefined); - var prevProps = getFiberCurrentPropsFromNode(node); - var prevValue = prevProps != null ? prevProps[name] : null; - - if (typeof prevValue === "function") { - node.removeEventListener(eventName, prevValue, useCapture); - } +function markRootEntangled(root, entangledLanes) { + // In addition to entangling each of the given lanes with each other, we also + // have to consider _transitive_ entanglements. For each lane that is already + // entangled with *any* of the given lanes, that lane is now transitively + // entangled with *all* the given lanes. + // + // Translated: If C is entangled with A, then entangling A with B also + // entangles C with B. + // + // If this is hard to grasp, it might help to intentionally break this + // function and look at the tests that fail in ReactTransition-test.js. Try + // commenting out one of the conditions below. + var rootEntangledLanes = (root.entangledLanes |= entangledLanes); + var entanglements = root.entanglements; + var lanes = rootEntangledLanes; - if (typeof value === "function") { - if (typeof prevValue !== "function" && prevValue !== null) { - // If we previously assigned a non-function type into this node, then - // remove it when switching to event listener mode. - if (name in node) { - node[name] = null; - } else if (node.hasAttribute(name)) { - node.removeAttribute(name); - } - } // $FlowFixMe value can't be casted to EventListener. + while (lanes) { + var index = pickArbitraryLaneIndex(lanes); + var lane = 1 << index; - node.addEventListener(eventName, value, useCapture); - return; + if ( + // Is this one of the newly entangled lanes? + (lane & entangledLanes) | // Is this lane transitively entangled with the newly entangled lanes? + (entanglements[index] & entangledLanes) + ) { + entanglements[index] |= entangledLanes; } + + lanes &= ~lane; } +} +function markHiddenUpdate(root, update, lane) { + var index = laneToIndex(lane); + var hiddenUpdates = root.hiddenUpdates; + var hiddenUpdatesForLane = hiddenUpdates[index]; - if (enableCustomElementPropertySupport && name in node) { - node[name] = value; - return; + if (hiddenUpdatesForLane === null) { + hiddenUpdates[index] = [update]; + } else { + hiddenUpdatesForLane.push(update); } - if (isAttributeNameSafe(name)) { - // shouldRemoveAttribute - if (value === null) { - node.removeAttribute(name); - return; - } + update.lane = lane | OffscreenLane; +} +function getBumpedLaneForHydration(root, renderLanes) { + var renderLane = getHighestPriorityLane(renderLanes); + var lane; - switch (typeof value) { - case "undefined": - case "function": - case "symbol": - // eslint-disable-line - node.removeAttribute(name); - return; + if (enableUnifiedSyncLane && (renderLane & SyncUpdateLanes) !== NoLane) { + lane = SyncHydrationLane; + } else { + switch (renderLane) { + case SyncLane: + lane = SyncHydrationLane; + break; - case "boolean": { - if (enableCustomElementPropertySupport) { - if (value === true) { - node.setAttribute(name, ""); - return; - } + case InputContinuousLane: + lane = InputContinuousHydrationLane; + break; - node.removeAttribute(name); - return; - } - } - } + case DefaultLane: + lane = DefaultHydrationLane; + break; - { - checkAttributeStringCoercion(value, name); + case TransitionLane1: + case TransitionLane2: + case TransitionLane3: + case TransitionLane4: + case TransitionLane5: + case TransitionLane6: + case TransitionLane7: + case TransitionLane8: + case TransitionLane9: + case TransitionLane10: + case TransitionLane11: + case TransitionLane12: + case TransitionLane13: + case TransitionLane14: + case TransitionLane15: + case TransitionLane16: + case RetryLane1: + case RetryLane2: + case RetryLane3: + case RetryLane4: + lane = TransitionHydrationLane; + break; + + case IdleLane: + lane = IdleHydrationLane; + break; + + default: + // Everything else is already either a hydration lane, or shouldn't + // be retried at a hydration lane. + lane = NoLane; + break; } + } // Check if the lane we chose is suspended. If so, that indicates that we + // already attempted and failed to hydrate at that level. Also check if we're + // already rendering that lane, which is rare but could happen. - node.setAttribute(name, enableTrustedTypesIntegration ? value : "" + value); + if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) { + // Give up trying to hydrate and fall back to client render. + return NoLane; } + + return lane; } +function addFiberToLanesMap(root, fiber, lanes) { + if (!isDevToolsPresent) { + return; + } -// Helpers to patch console.logs to avoid logging during side-effect free -// replaying on render function. This currently only patches the object -// lazily which won't cover if the log function was extracted eagerly. -// We could also eagerly patch the method. -var disabledDepth = 0; -var prevLog; -var prevInfo; -var prevWarn; -var prevError; -var prevGroup; -var prevGroupCollapsed; -var prevGroupEnd; + var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; -function disabledLog() {} + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var updaters = pendingUpdatersLaneMap[index]; + updaters.add(fiber); + lanes &= ~lane; + } +} +function movePendingFibersToMemoized(root, lanes) { + if (!isDevToolsPresent) { + return; + } -disabledLog.__reactDisabledLog = true; -function disableLogs() { - { - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - prevLog = console.log; - prevInfo = console.info; - prevWarn = console.warn; - prevError = console.error; - prevGroup = console.group; - prevGroupCollapsed = console.groupCollapsed; - prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099 + var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; + var memoizedUpdaters = root.memoizedUpdaters; - var props = { - configurable: true, - enumerable: true, - value: disabledLog, - writable: true - }; // $FlowFixMe Flow thinks console is immutable. + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var updaters = pendingUpdatersLaneMap[index]; - Object.defineProperties(console, { - info: props, - log: props, - warn: props, - error: props, - group: props, - groupCollapsed: props, - groupEnd: props + if (updaters.size > 0) { + updaters.forEach(function (fiber) { + var alternate = fiber.alternate; + + if (alternate === null || !memoizedUpdaters.has(alternate)) { + memoizedUpdaters.add(fiber); + } }); - /* eslint-enable react-internal/no-production-logging */ + updaters.clear(); } - disabledDepth++; + lanes &= ~lane; } } -function reenableLogs() { - { - disabledDepth--; - - if (disabledDepth === 0) { - /* eslint-disable react-internal/no-production-logging */ - var props = { - configurable: true, - enumerable: true, - writable: true - }; // $FlowFixMe Flow thinks console is immutable. +function addTransitionToLanesMap(root, transition, lane) { + if (enableTransitionTracing) { + var transitionLanesMap = root.transitionLanes; + var index = laneToIndex(lane); + var transitions = transitionLanesMap[index]; - Object.defineProperties(console, { - log: assign({}, props, { - value: prevLog - }), - info: assign({}, props, { - value: prevInfo - }), - warn: assign({}, props, { - value: prevWarn - }), - error: assign({}, props, { - value: prevError - }), - group: assign({}, props, { - value: prevGroup - }), - groupCollapsed: assign({}, props, { - value: prevGroupCollapsed - }), - groupEnd: assign({}, props, { - value: prevGroupEnd - }) - }); - /* eslint-enable react-internal/no-production-logging */ + if (transitions === null) { + transitions = new Set(); } - if (disabledDepth < 0) { - error( - "disabledDepth fell below zero. " + - "This is a bug in React. Please file an issue." - ); - } + transitions.add(transition); + transitionLanesMap[index] = transitions; } } +function getTransitionsForLanes(root, lanes) { + if (!enableTransitionTracing) { + return null; + } -var ReactCurrentDispatcher$2 = ReactSharedInternals.ReactCurrentDispatcher; -var prefix; -function describeBuiltInComponentFrame(name, source, ownerFn) { - { - if (prefix === undefined) { - // Extract the VM specific prefix used by each line. - try { - throw Error(); - } catch (x) { - var match = x.stack.trim().match(/\n( *(at )?)/); - prefix = (match && match[1]) || ""; - } - } // We use the prefix to ensure our stacks line up with native stack frames. + var transitionsForLanes = []; - return "\n" + prefix + name; - } -} -var reentry = false; -var componentFrameCache; + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var transitions = root.transitionLanes[index]; -{ - var PossiblyWeakMap$2 = typeof WeakMap === "function" ? WeakMap : Map; - componentFrameCache = new PossiblyWeakMap$2(); -} + if (transitions !== null) { + transitions.forEach(function (transition) { + transitionsForLanes.push(transition); + }); + } -function describeNativeComponentFrame(fn, construct) { - // If something asked for a stack inside a fake render, it should get ignored. - if (disableNativeComponentFrames || !fn || reentry) { - return ""; + lanes &= ~lane; } - { - var frame = componentFrameCache.get(fn); - - if (frame !== undefined) { - return frame; - } + if (transitionsForLanes.length === 0) { + return null; } - var control; - reentry = true; - var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined. + return transitionsForLanes; +} +function clearTransitionsForLanes(root, lanes) { + if (!enableTransitionTracing) { + return; + } - Error.prepareStackTrace = undefined; - var previousDispatcher; + while (lanes > 0) { + var index = laneToIndex(lanes); + var lane = 1 << index; + var transitions = root.transitionLanes[index]; - { - previousDispatcher = ReactCurrentDispatcher$2.current; // Set the dispatcher in DEV because this might be call in the render function - // for warnings. + if (transitions !== null) { + root.transitionLanes[index] = null; + } - ReactCurrentDispatcher$2.current = null; - disableLogs(); + lanes &= ~lane; } +} - try { - // This should throw. - if (construct) { - // Something should be setting the props in the constructor. - var Fake = function () { - throw Error(); - }; // $FlowFixMe - - Object.defineProperty(Fake.prototype, "props", { - set: function () { - // We use a throwing setter instead of frozen or non-writable props - // because that won't throw in a non-strict mode function. - throw Error(); - } - }); - - if (typeof Reflect === "object" && Reflect.construct) { - // We construct a different control for this case to include any extra - // frames added by the construct call. - try { - Reflect.construct(Fake, []); - } catch (x) { - control = x; - } - - Reflect.construct(fn, [], Fake); - } else { - try { - Fake.call(); - } catch (x) { - control = x; - } // $FlowFixMe[prop-missing] found when upgrading Flow - - fn.call(Fake.prototype); - } - } else { - try { - throw Error(); - } catch (x) { - control = x; - } // TODO(luna): This will currently only throw if the function component - // tries to access React/ReactDOM/props. We should probably make this throw - // in simple components too - - fn(); - } - } catch (sample) { - // This is inlined manually because closure doesn't do it for us. - if (sample && control && typeof sample.stack === "string") { - // This extracts the first frame from the sample that isn't also in the control. - // Skipping one frame that we assume is the frame that calls the two. - var sampleLines = sample.stack.split("\n"); - var controlLines = control.stack.split("\n"); - var s = sampleLines.length - 1; - var c = controlLines.length - 1; - - while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { - // We expect at least one stack frame to be shared. - // Typically this will be the root most one. However, stack frames may be - // cut off due to maximum stack limits. In this case, one maybe cut off - // earlier than the other. We assume that the sample is longer or the same - // and there for cut off earlier. So we should find the root most frame in - // the sample somewhere in the control. - c--; - } - - for (; s >= 1 && c >= 0; s--, c--) { - // Next we find the first one that isn't the same which should be the - // frame that called our sample function and the control. - if (sampleLines[s] !== controlLines[c]) { - // In V8, the first line is describing the message but other VMs don't. - // If we're about to return the first line, and the control is also on the same - // line, that's a pretty good indicator that our sample threw at same line as - // the control. I.e. before we entered the sample frame. So we ignore this result. - // This can happen if you passed a class to function component, or non-function. - if (s !== 1 || c !== 1) { - do { - s--; - c--; // We may still have similar intermediate frames from the construct call. - // The next one that isn't the same should be our match though. - - if (c < 0 || sampleLines[s] !== controlLines[c]) { - // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. - var _frame = "\n" + sampleLines[s].replace(" at new ", " at "); // If our component frame is labeled "" - // but we have a user-provided "displayName" - // splice it in to make the stack more readable. - - if (fn.displayName && _frame.includes("")) { - _frame = _frame.replace("", fn.displayName); - } - - { - if (typeof fn === "function") { - componentFrameCache.set(fn, _frame); - } - } // Return the line we found. - - return _frame; - } - } while (s >= 1 && c >= 0); - } +var DiscreteEventPriority = SyncLane; +var ContinuousEventPriority = InputContinuousLane; +var DefaultEventPriority = DefaultLane; +var IdleEventPriority = IdleLane; +var currentUpdatePriority = NoLane; +function getCurrentUpdatePriority() { + return currentUpdatePriority; +} +function setCurrentUpdatePriority(newPriority) { + currentUpdatePriority = newPriority; +} +function runWithPriority(priority, fn) { + var previousPriority = currentUpdatePriority; - break; - } - } - } + try { + currentUpdatePriority = priority; + return fn(); } finally { - reentry = false; - - { - ReactCurrentDispatcher$2.current = previousDispatcher; - reenableLogs(); - } - - Error.prepareStackTrace = previousPrepareStackTrace; - } // Fallback to just using the name if we couldn't make it throw. - - var name = fn ? fn.displayName || fn.name : ""; - var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; - - { - if (typeof fn === "function") { - componentFrameCache.set(fn, syntheticFrame); - } + currentUpdatePriority = previousPriority; } - - return syntheticFrame; } - -function describeClassComponentFrame(ctor, source, ownerFn) { - { - return describeNativeComponentFrame(ctor, true); - } +function higherEventPriority(a, b) { + return a !== 0 && a < b ? a : b; } -function describeFunctionComponentFrame(fn, source, ownerFn) { - { - return describeNativeComponentFrame(fn, false); - } +function lowerEventPriority(a, b) { + return a === 0 || a > b ? a : b; } - -function shouldConstruct$1(Component) { - var prototype = Component.prototype; - return !!(prototype && prototype.isReactComponent); +function isHigherEventPriority(a, b) { + return a !== 0 && a < b; } +function lanesToEventPriority(lanes) { + var lane = getHighestPriorityLane(lanes); -function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { - if (type == null) { - return ""; - } - - if (typeof type === "function") { - { - return describeNativeComponentFrame(type, shouldConstruct$1(type)); - } - } - - if (typeof type === "string") { - return describeBuiltInComponentFrame(type); + if (!isHigherEventPriority(DiscreteEventPriority, lane)) { + return DiscreteEventPriority; } - switch (type) { - case REACT_SUSPENSE_TYPE: - return describeBuiltInComponentFrame("Suspense"); - - case REACT_SUSPENSE_LIST_TYPE: - return describeBuiltInComponentFrame("SuspenseList"); + if (!isHigherEventPriority(ContinuousEventPriority, lane)) { + return ContinuousEventPriority; } - if (typeof type === "object") { - switch (type.$$typeof) { - case REACT_FORWARD_REF_TYPE: - return describeFunctionComponentFrame(type.render); - - case REACT_MEMO_TYPE: - // Memo may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); - - case REACT_LAZY_TYPE: { - var lazyComponent = type; - var payload = lazyComponent._payload; - var init = lazyComponent._init; - - try { - // Lazy may contain any component type so we recursively resolve it. - return describeUnknownElementTypeFrameInDEV( - init(payload), - source, - ownerFn - ); - } catch (x) {} - } - } + if (includesNonIdleWork(lane)) { + return DefaultEventPriority; } - return ""; -} - -function describeFiber(fiber) { - switch (fiber.tag) { - case HostHoistable: - case HostSingleton: - case HostComponent: - return describeBuiltInComponentFrame(fiber.type); - - case LazyComponent: - return describeBuiltInComponentFrame("Lazy"); - - case SuspenseComponent: - return describeBuiltInComponentFrame("Suspense"); - - case SuspenseListComponent: - return describeBuiltInComponentFrame("SuspenseList"); - - case FunctionComponent: - case IndeterminateComponent: - case SimpleMemoComponent: - return describeFunctionComponentFrame(fiber.type); - - case ForwardRef: - return describeFunctionComponentFrame(fiber.type.render); - - case ClassComponent: - return describeClassComponentFrame(fiber.type); - - default: - return ""; - } + return IdleEventPriority; } -function getStackByFiberInDevAndProd(workInProgress) { - try { - var info = ""; - var node = workInProgress; - - do { - info += describeFiber(node); // $FlowFixMe[incompatible-type] we bail out when we get a null +// $FlowFixMe[method-unbinding] +var hasOwnProperty = Object.prototype.hasOwnProperty; - node = node.return; - } while (node); +/* + * The `'' + value` pattern (used in perf-sensitive code) throws for Symbol + * and Temporal.* types. See https://github.com/facebook/react/pull/22064. + * + * The functions in this module will throw an easier-to-understand, + * easier-to-debug exception with a clear errors message message explaining the + * problem. (Instead of a confusing exception thrown inside the implementation + * of the `value` object). + */ +// $FlowFixMe only called in DEV, so void return is not possible. +function typeName(value) { + { + // toStringTag is needed for namespaced types like Temporal.Instant + var hasToStringTag = typeof Symbol === "function" && Symbol.toStringTag; + var type = + (hasToStringTag && value[Symbol.toStringTag]) || + value.constructor.name || + "Object"; // $FlowFixMe - return info; - } catch (x) { - return "\nError generating stack: " + x.message + "\n" + x.stack; + return type; } -} +} // $FlowFixMe only called in DEV, so void return is not possible. -var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; -var current = null; -var isRendering = false; -function getCurrentFiberOwnerNameInDevOrNull() { +function willCoercionThrow(value) { { - if (current === null) { - return null; - } - - var owner = current._debugOwner; - - if (owner !== null && typeof owner !== "undefined") { - return getComponentNameFromFiber(owner); + try { + testStringCoercion(value); + return false; + } catch (e) { + return true; } } +} - return null; +function testStringCoercion(value) { + // If you ended up here by following an exception call stack, here's what's + // happened: you supplied an object or symbol value to React (as a prop, key, + // DOM attribute, CSS property, string ref, etc.) and when React tried to + // coerce it to a string using `'' + value`, an exception was thrown. + // + // The most common types that will cause this exception are `Symbol` instances + // and Temporal objects like `Temporal.Instant`. But any object that has a + // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this + // exception. (Library authors do this to prevent users from using built-in + // numeric operators like `+` or comparison operators like `>=` because custom + // methods are needed to perform accurate arithmetic or comparison.) + // + // To fix the problem, coerce this object or symbol value to a string before + // passing it to React. The most reliable way is usually `String(value)`. + // + // To find which value is throwing, check the browser or debugger console. + // Before this exception was thrown, there should be `console.error` output + // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the + // problem and how that type was used: key, atrribute, input value prop, etc. + // In most cases, this console output also shows the component and its + // ancestor components where the exception happened. + // + // eslint-disable-next-line react-internal/safe-string-coercion + return "" + value; } -function getCurrentFiberStackInDev() { +function checkAttributeStringCoercion(value, attributeName) { { - if (current === null) { - return ""; - } // Safe because if current fiber exists, we are reconciling, - // and it is guaranteed to be the work-in-progress version. + if (willCoercionThrow(value)) { + error( + "The provided `%s` attribute is an unsupported type %s." + + " This value must be coerced to a string before before using it here.", + attributeName, + typeName(value) + ); - return getStackByFiberInDevAndProd(current); + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } } - -function resetCurrentFiber() { +function checkKeyStringCoercion(value) { { - ReactDebugCurrentFrame$1.getCurrentStack = null; - current = null; - isRendering = false; + if (willCoercionThrow(value)) { + error( + "The provided key is an unsupported type %s." + + " This value must be coerced to a string before before using it here.", + typeName(value) + ); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } } -function setCurrentFiber(fiber) { +function checkPropStringCoercion(value, propName) { { - ReactDebugCurrentFrame$1.getCurrentStack = - fiber === null ? null : getCurrentFiberStackInDev; - current = fiber; - isRendering = false; + if (willCoercionThrow(value)) { + error( + "The provided `%s` prop is an unsupported type %s." + + " This value must be coerced to a string before before using it here.", + propName, + typeName(value) + ); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } } -function getCurrentFiber() { +function checkCSSPropertyStringCoercion(value, propName) { { - return current; + if (willCoercionThrow(value)) { + error( + "The provided `%s` CSS property is an unsupported type %s." + + " This value must be coerced to a string before before using it here.", + propName, + typeName(value) + ); + + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } } -function setIsRendering(rendering) { +function checkHtmlStringCoercion(value) { { - isRendering = rendering; - } -} - -// around this limitation, we use an opaque type that can only be obtained by -// passing the value through getToStringValue first. - -function toString(value) { - // The coercion safety check is performed in getToStringValue(). - // eslint-disable-next-line react-internal/safe-string-coercion - return "" + value; -} -function getToStringValue(value) { - switch (typeof value) { - case "boolean": - case "number": - case "string": - case "undefined": - return value; - - case "object": - { - checkFormFieldValueStringCoercion(value); - } - - return value; + if (willCoercionThrow(value)) { + error( + "The provided HTML markup uses a value of unsupported type %s." + + " This value must be coerced to a string before before using it here.", + typeName(value) + ); - default: - // function, symbol are assigned as empty strings - return ""; + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) + } } } - -var hasReadOnlyValue = { - button: true, - checkbox: true, - image: true, - hidden: true, - radio: true, - reset: true, - submit: true -}; -function checkControlledValueProps(tagName, props) { +function checkFormFieldValueStringCoercion(value) { { - if ( - !( - hasReadOnlyValue[props.type] || - props.onChange || - props.onInput || - props.readOnly || - props.disabled || - props.value == null - ) - ) { + if (willCoercionThrow(value)) { error( - "You provided a `value` prop to a form field without an " + - "`onChange` handler. This will render a read-only field. If " + - "the field should be mutable use `defaultValue`. Otherwise, " + - "set either `onChange` or `readOnly`." + "Form field values (value, checked, defaultValue, or defaultChecked props)" + + " must be strings, not %s." + + " This value must be coerced to a string before before using it here.", + typeName(value) ); - } - if ( - !( - props.onChange || - props.readOnly || - props.disabled || - props.checked == null - ) - ) { - error( - "You provided a `checked` prop to a form field without an " + - "`onChange` handler. This will render a read-only field. If " + - "the field should be mutable use `defaultChecked`. Otherwise, " + - "set either `onChange` or `readOnly`." - ); + return testStringCoercion(value); // throw (to help callers find troubleshooting comments) } } } -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; -} +var Internals = { + usingClientEntryPoint: false, + Events: null, + Dispatcher: { + current: null + } +}; -function detachTracker(node) { - node._valueTracker = null; -} +var canUseDOM = !!( + typeof window !== "undefined" && + typeof window.document !== "undefined" && + typeof window.document.createElement !== "undefined" +); -function getValueFromNode(node) { - var value = ""; +// Attributes that aren't in the filter are presumed to have this type. - if (!node) { - return value; - } +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. - if (isCheckable(node)) { - value = node.checked ? "true" : "false"; - } else { - value = node.value; - } +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. - return value; -} - -function trackValueOnNode(node) { - var valueField = isCheckable(node) ? "checked" : "value"; - var descriptor = Object.getOwnPropertyDescriptor( - node.constructor.prototype, - valueField - ); - - { - checkFormFieldValueStringCoercion(node[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 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 get = descriptor.get, - set = descriptor.set; - Object.defineProperty(node, valueField, { - configurable: true, - // $FlowFixMe[missing-this-annot] - get: function () { - return get.call(this); - }, - // $FlowFixMe[missing-local-annot] - // $FlowFixMe[missing-this-annot] - set: function (value) { - { - checkFormFieldValueStringCoercion(value); - } +var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric. +// When falsy, it should be removed. - 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. - // https://github.com/facebook/react/issues/11768 +var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric. +// When falsy, it should be removed. - Object.defineProperty(node, valueField, { - enumerable: descriptor.enumerable - }); - var tracker = { - getValue: function () { - return currentValue; - }, - setValue: function (value) { - { - checkFormFieldValueStringCoercion(value); - } +var POSITIVE_NUMERIC = 6; +/* eslint-disable max-len */ - currentValue = "" + value; - }, - stopTracking: function () { - detachTracker(node); - delete node[valueField]; - } - }; - return tracker; -} +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 */ -function track(node) { - if (getTracker(node)) { - return; - } // TODO: Once it's just Fiber we can move this to node._wrapperState +var ATTRIBUTE_NAME_CHAR = + ATTRIBUTE_NAME_START_CHAR + "\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; +var VALID_ATTRIBUTE_NAME_REGEX = new RegExp( + "^[" + ATTRIBUTE_NAME_START_CHAR + "][" + ATTRIBUTE_NAME_CHAR + "]*$" +); +var illegalAttributeNameCache = {}; +var validatedAttributeNameCache = {}; +function isAttributeNameSafe(attributeName) { + if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) { + return true; + } - node._valueTracker = trackValueOnNode(node); -} -function updateValueIfChanged(node) { - if (!node) { + if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) { return false; } - var tracker = getTracker(node); // if there is no tracker at this point it's unlikely - // that trying again will succeed - - if (!tracker) { + if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) { + validatedAttributeNameCache[attributeName] = true; return true; } - var lastValue = tracker.getValue(); - var nextValue = getValueFromNode(node); + illegalAttributeNameCache[attributeName] = true; - if (nextValue !== lastValue) { - tracker.setValue(nextValue); - return true; + { + error("Invalid attribute name: `%s`", attributeName); } return false; } +function getPropertyInfo(name) { + return properties.hasOwnProperty(name) ? properties[name] : null; +} // $FlowFixMe[missing-this-annot] -function getActiveElement(doc) { - doc = doc || (typeof document !== "undefined" ? document : undefined); +function PropertyInfoRecord( + name, + type, + mustUseProperty, + attributeName, + attributeNamespace, + sanitizeURL, + removeEmptyString +) { + 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; + this.sanitizeURL = sanitizeURL; + this.removeEmptyString = removeEmptyString; +} // When adding attributes to this list, be sure to also add them to +// the `possibleStandardNames` module to ensure casing and incorrect +// name warnings. - if (typeof doc === "undefined") { - return null; - } +var properties = {}; // A few React string attributes have a different name. +// This is a mapping from React prop names to the attribute names. - try { - return doc.activeElement || doc.body; - } catch (e) { - return doc.body; - } -} +[ + ["acceptCharset", "accept-charset"], + ["className", "class"], + ["htmlFor", "for"], + ["httpEquiv", "http-equiv"] +].forEach(function (_ref) { + var name = _ref[0], + attributeName = _ref[1]; + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + STRING, + false, // mustUseProperty + attributeName, // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // 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). -var didWarnValueDefaultValue$1 = false; -var didWarnCheckedDefaultChecked = false; -var didWarnControlledToUncontrolled = false; -var didWarnUncontrolledToControlled = false; +["contentEditable", "draggable", "spellCheck", "value"].forEach(function ( + name +) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + BOOLEANISH_STRING, + false, // mustUseProperty + name.toLowerCase(), // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // 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. -function isControlled(props) { - var usesChecked = props.type === "checkbox" || props.type === "radio"; - return usesChecked ? props.checked != null : props.value != null; -} -/** - * Implements an 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`). - * - * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html - */ +[ + "autoReverse", + "externalResourcesRequired", + "focusable", + "preserveAlpha" +].forEach(function (name) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + BOOLEANISH_STRING, + false, // mustUseProperty + name, // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // These are HTML boolean attributes. -function getHostProps$2(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$2(element, props) { - { - checkControlledValueProps("input", props); +[ + "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", + "disablePictureInPicture", + "disableRemotePlayback", + "formNoValidate", + "hidden", + "loop", + "noModule", + "noValidate", + "open", + "playsInline", + "readOnly", + "required", + "reversed", + "scoped", + "seamless", // Microdata + "itemScope" +].forEach(function (name) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + BOOLEAN, + false, // mustUseProperty + name.toLowerCase(), // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // These are the few React props that we set as DOM properties +// rather than attributes. These are all booleans. - if ( - props.checked !== undefined && - props.defaultChecked !== undefined && - !didWarnCheckedDefaultChecked - ) { - error( - "%s contains an input of type %s with both checked and defaultChecked props. " + - "Input elements must be either controlled or uncontrolled " + - "(specify either the checked prop, or the defaultChecked prop, but not " + - "both). Decide between using a controlled or uncontrolled input " + - "element and remove one of these props. More info: " + - "https://reactjs.org/link/controlled-components", - getCurrentFiberOwnerNameInDevOrNull() || "A component", - props.type - ); +[ + "checked", // Note: `option.selected` is not updated if `select.multiple` is + // disabled with `removeAttribute`. We have special logic for handling this. + "multiple", + "muted", + "selected" // NOTE: if you add a camelCased prop to this list, + // you'll need to set attributeName to name.toLowerCase() + // instead in the assignment below. +].forEach(function (name) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + BOOLEAN, + true, // mustUseProperty + name, // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // These are HTML attributes that are "overloaded booleans": they behave like +// booleans, but can also accept a string value. - didWarnCheckedDefaultChecked = true; - } +[ + "capture", + "download" // NOTE: if you add a camelCased prop to this list, + // you'll need to set attributeName to name.toLowerCase() + // instead in the assignment below. +].forEach(function (name) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + OVERLOADED_BOOLEAN, + false, // mustUseProperty + name, // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // These are HTML attributes that must be positive numbers. - if ( - props.value !== undefined && - props.defaultValue !== undefined && - !didWarnValueDefaultValue$1 - ) { - error( - "%s contains an input of type %s with both value and defaultValue props. " + - "Input elements must be either controlled or uncontrolled " + - "(specify either the value prop, or the defaultValue prop, but not " + - "both). Decide between using a controlled or uncontrolled input " + - "element and remove one of these props. More info: " + - "https://reactjs.org/link/controlled-components", - getCurrentFiberOwnerNameInDevOrNull() || "A component", - props.type - ); +[ + "cols", + "rows", + "size", + "span" // NOTE: if you add a camelCased prop to this list, + // you'll need to set attributeName to name.toLowerCase() + // instead in the assignment below. +].forEach(function (name) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + POSITIVE_NUMERIC, + false, // mustUseProperty + name, // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // These are HTML attributes that must be numbers. - didWarnValueDefaultValue$1 = true; - } - } +["rowSpan", "start"].forEach(function (name) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[name] = new PropertyInfoRecord( + name, + NUMERIC, + false, // mustUseProperty + name.toLowerCase(), // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); +var CAMELIZE = /[\-\:]([a-z])/g; - 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; +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 attribute filter. +// Some of these attributes can be hard to find. This list was created by +// scraping the MDN documentation. - if (checked != null) { - node.checked = checked; - } -} -function updateWrapper$1(element, props) { - var node = element; +[ + "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", + "transform-origin", + "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" // NOTE: if you add a camelCased prop to this list, + // you'll need to set attributeName to name.toLowerCase() + // instead in the assignment below. +].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - { - var controlled = isControlled(props); + properties[name] = new PropertyInfoRecord( + name, + STRING, + false, // mustUseProperty + attributeName, + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // String SVG attributes with the xlink namespace. - if ( - !node._wrapperState.controlled && - controlled && - !didWarnUncontrolledToControlled - ) { - error( - "A component is changing an uncontrolled input to be controlled. " + - "This is likely caused by the value changing from undefined to " + - "a defined value, which should not happen. " + - "Decide between using a controlled or uncontrolled input " + - "element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components" - ); +[ + "xlink:actuate", + "xlink:arcrole", + "xlink:role", + "xlink:show", + "xlink:title", + "xlink:type" // NOTE: if you add a camelCased prop to this list, + // you'll need to set attributeName to name.toLowerCase() + // instead in the assignment below. +].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - didWarnUncontrolledToControlled = true; - } + properties[name] = new PropertyInfoRecord( + name, + STRING, + false, // mustUseProperty + attributeName, + "http://www.w3.org/1999/xlink", + false, // sanitizeURL + false + ); +}); // String SVG attributes with the xml namespace. - if ( - node._wrapperState.controlled && - !controlled && - !didWarnControlledToUncontrolled - ) { - error( - "A component is changing a controlled input to be uncontrolled. " + - "This is likely caused by the value changing from a defined to " + - "undefined, which should not happen. " + - "Decide between using a controlled or uncontrolled input " + - "element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components" - ); +[ + "xml:base", + "xml:lang", + "xml:space" // NOTE: if you add a camelCased prop to this list, + // you'll need to set attributeName to name.toLowerCase() + // instead in the assignment below. +].forEach(function (attributeName) { + var name = attributeName.replace(CAMELIZE, capitalize); // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - didWarnControlledToUncontrolled = true; - } - } + properties[name] = new PropertyInfoRecord( + name, + STRING, + false, // mustUseProperty + attributeName, + "http://www.w3.org/XML/1998/namespace", + false, // sanitizeURL + false + ); +}); // 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. - updateChecked(element, props); - var value = getToStringValue(props.value); - var type = props.type; +["tabIndex", "crossOrigin"].forEach(function (attributeName) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[attributeName] = new PropertyInfoRecord( + attributeName, + STRING, + false, // mustUseProperty + attributeName.toLowerCase(), // attributeName + null, // attributeNamespace + false, // sanitizeURL + false + ); +}); // These attributes accept URLs. These must not allow javascript: URLS. +// These will also need to accept Trusted Types object in the future. - if (value != null) { - if (type === "number") { - if ( - // $FlowFixMe[incompatible-type] - (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; - } +var xlinkHref = "xlinkHref"; // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - 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)); - } - } +properties[xlinkHref] = new PropertyInfoRecord( + "xlinkHref", + STRING, + false, // mustUseProperty + "xlink:href", + "http://www.w3.org/1999/xlink", + true, // sanitizeURL + false +); +var formAction = "formAction"; // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions - 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; +properties[formAction] = new PropertyInfoRecord( + "formAction", + STRING, + false, // mustUseProperty + "formaction", // attributeName + null, // attributeNamespace + true, // sanitizeURL + false +); +["src", "href", "action"].forEach(function (attributeName) { + // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions + properties[attributeName] = new PropertyInfoRecord( + attributeName, + STRING, + false, // mustUseProperty + attributeName.toLowerCase(), // attributeName + null, // attributeNamespace + true, // sanitizeURL + true + ); +}); + +// and any newline or tab are filtered out as if they're not part of the URL. +// https://url.spec.whatwg.org/#url-parsing +// Tab or newline are defined as \r\n\t: +// https://infra.spec.whatwg.org/#ascii-tab-or-newline +// A C0 control is a code point in the range \u0000 NULL to \u001F +// INFORMATION SEPARATOR ONE, inclusive: +// https://infra.spec.whatwg.org/#c0-control-or-space + +/* eslint-disable max-len */ + +var isJavaScriptProtocol = + /^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i; + +function sanitizeURL(url) { + { + if (isJavaScriptProtocol.test(url)) { + throw new Error( + "React has blocked a javascript: URL as a security precaution." + ); } } } -function postMountWrapper$3(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 +/** + * 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. + */ - if (isButton && (props.value === undefined || props.value === null)) { - return; +function getValueForProperty(node, name, expected, propertyInfo) { + { + if (propertyInfo.mustUseProperty) { + var propertyName = propertyInfo.propertyName; + return node[propertyName]; } - 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. + var attributeName = propertyInfo.attributeName; - 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 (!node.hasAttribute(attributeName)) { + // shouldRemoveAttribute + switch (typeof expected) { + case "function": + case "symbol": + // eslint-disable-line + return expected; - 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); + case "boolean": { + if (!propertyInfo.acceptsBooleans) { + return expected; } } - } 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); + switch (propertyInfo.type) { + case BOOLEAN: { + if (!expected) { + return expected; + } - 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). - // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416 - // We need to temporarily unset name to avoid disrupting radio button groups. + break; + } - var name = node.name; + case OVERLOADED_BOOLEAN: { + if (expected === false) { + return expected; + } - if (name !== "") { - node.name = ""; - } + break; + } - 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) + case NUMERIC: { + if (isNaN(expected)) { + return expected; + } - 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; - } + break; + } - if (name !== "") { - node.name = name; - } -} -function restoreControlledState$3(element, props) { - var node = element; - updateWrapper$1(node, props); - updateNamedCousins(node, props); -} + case POSITIVE_NUMERIC: { + if (isNaN(expected) || expected < 1) { + return expected; + } -function updateNamedCousins(rootNode, props) { - var name = props.name; + break; + } + } - if (props.type === "radio" && name != null) { - var queryRoot = rootNode; + { + if (propertyInfo.removeEmptyString && expected === "") { + { + if (name === "src") { + error( + 'An empty string ("") was passed to the %s attribute. ' + + "This may cause the browser to download the whole page again over the network. " + + "To fix this, either do not render the element at all " + + "or pass null to %s instead of an empty string.", + name, + name + ); + } else { + error( + 'An empty string ("") was passed to the %s attribute. ' + + "To fix this, either do not render the element at all " + + "or pass null to %s instead of an empty string.", + name, + name + ); + } + } - 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. + return expected; + } + } - { - checkAttributeStringCoercion(name, "name"); - } + return expected === undefined ? undefined : null; + } // Even if this property uses a namespace we use getAttribute + // because we assume its namespaced name is the same as our config. + // To use getAttributeNS we need the local name which we don't have + // in our config atm. - var group = queryRoot.querySelectorAll( - "input[name=" + JSON.stringify("" + name) + '][type="radio"]' - ); + var value = node.getAttribute(attributeName); - for (var i = 0; i < group.length; i++) { - var otherNode = group[i]; + if (expected == null) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } // shouldRemoveAttribute - 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. + switch (propertyInfo.type) { + case BOOLEAN: { + if (expected) { + // If this was a boolean, it doesn't matter what the value is + // the fact that we have it is the same as the expected. + // As long as it's positive. + return expected; + } - var otherProps = getFiberCurrentPropsFromNode(otherNode); + return value; + } - if (!otherProps) { - throw new Error( - "ReactDOMInput: Mixing React and non-React radio inputs with the " + - "same `name` is not supported." - ); - } // We need update the tracked value on the named cousin since the value - // was changed but the input saw no event or value set + case OVERLOADED_BOOLEAN: { + if (value === "") { + return true; + } - 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. + if (expected === false) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } - updateWrapper$1(otherNode, otherProps); + break; + } + + case NUMERIC: { + if (isNaN(expected)) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } + + break; + } + + case POSITIVE_NUMERIC: { + if (isNaN(expected) || expected < 1) { + // We had an attribute but shouldn't have had one, so read it + // for the error message. + return value; + } + + break; + } } - } -} // 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 is not a valid email address". -// -// Here we check to see if the defaultValue has actually changed, avoiding these problems -// when the user is inputting text -// -// https://github.com/facebook/react/issues/7253 -function setDefaultValue(node, type, value) { - if ( - // Focused number inputs synchronize on blur. See ChangeEventPlugin.js - type !== "number" || - getActiveElement(node.ownerDocument) !== node - ) { - if (value == null) { - node.defaultValue = toString(node._wrapperState.initialValue); - } else if (node.defaultValue !== toString(value)) { - node.defaultValue = toString(value); + { + checkAttributeStringCoercion(expected, name); + } + + if (value === "" + expected) { + return expected; } + + return value; } } - -var didWarnSelectedSetOnOption = false; -var didWarnInvalidChild = false; -var didWarnInvalidInnerHTML = false; /** - * Implements an