From 104322b932e38d147806b72a08ce2e5a1e94bbd5 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Wed, 14 May 2025 17:48:47 -0400 Subject: [PATCH 1/2] Prevent comment node roots from erroring when enableViewTransition=true --- .../react-dom-bindings/src/client/ReactFiberConfigDOM.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 5aa26b26340..d16b43da922 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -1593,8 +1593,10 @@ export function restoreRootViewTransitionName(rootContainer: Container): void { // clone the whole document outside of the React too. containerInstance = (rootContainer: any); } - // $FlowFixMe[prop-missing] - if (containerInstance.style.viewTransitionName === 'root') { + if ( + containerInstance.style && + containerInstance.style.viewTransitionName === 'root' + ) { // If we moved the root view transition name to the container in a gesture // we need to restore it now. containerInstance.style.viewTransitionName = ''; From 33b59317919d6f24fe1cf8f28d6aef358c986642 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Fri, 16 May 2025 10:07:06 -0400 Subject: [PATCH 2/2] Skip cancel/restore name on comment nodes and warn in DEV --- .../src/client/ReactFiberConfigDOM.js | 28 ++++++++++++++++++- .../src/ReactFiberCommitWork.js | 5 +++- scripts/error-codes/codes.json | 3 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index d16b43da922..4a3d5b00bf2 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -1549,6 +1549,19 @@ export function cancelRootViewTransitionName(rootContainer: Container): void { rootContainer.nodeType === DOCUMENT_NODE ? (rootContainer: any).documentElement : rootContainer.ownerDocument.documentElement; + + if ( + !disableCommentsAsDOMContainers && + rootContainer.nodeType === COMMENT_NODE + ) { + if (__DEV__) { + console.warn( + 'Cannot cancel root view transition on a comment node. All view transitions will be globally scoped.', + ); + } + return; + } + if ( documentElement !== null && // $FlowFixMe[prop-missing] @@ -1594,7 +1607,13 @@ export function restoreRootViewTransitionName(rootContainer: Container): void { containerInstance = (rootContainer: any); } if ( - containerInstance.style && + !disableCommentsAsDOMContainers && + containerInstance.nodeType === COMMENT_NODE + ) { + return; + } + if ( + // $FlowFixMe[prop-missing] containerInstance.style.viewTransitionName === 'root' ) { // If we moved the root view transition name to the container in a gesture @@ -1710,6 +1729,13 @@ export function cloneRootViewTransitionContainer( containerInstance = (rootContainer: any).body; } else if (rootContainer.nodeName === 'HTML') { containerInstance = (rootContainer.ownerDocument.body: any); + } else if ( + !disableCommentsAsDOMContainers && + rootContainer.nodeType === COMMENT_NODE + ) { + throw new Error( + 'Cannot use a startGestureTransition() with a comment node root.', + ); } else { // If the container is not the whole document, then we ideally should probably // clone the whole document outside of the React too. diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index e21271f3b3e..89d51bb42e6 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -306,6 +306,7 @@ export let shouldFireAfterActiveInstanceBlur: boolean = false; let viewTransitionContextChanged: boolean = false; let inUpdateViewTransition: boolean = false; let rootViewTransitionAffected: boolean = false; +let rootViewTransitionNameCanceled: boolean = false; function isHydratingParent(current: Fiber, finishedWork: Fiber): boolean { if (finishedWork.tag === ActivityComponent) { @@ -2737,6 +2738,7 @@ function commitAfterMutationEffectsOnFiber( switch (finishedWork.tag) { case HostRoot: { viewTransitionContextChanged = false; + rootViewTransitionNameCanceled = false; pushViewTransitionCancelableScope(); recursivelyTraverseAfterMutationEffects(root, finishedWork, lanes); if (!viewTransitionContextChanged && !rootViewTransitionAffected) { @@ -2755,6 +2757,7 @@ function commitAfterMutationEffectsOnFiber( } // We also cancel the root itself. cancelRootViewTransitionName(root.containerInfo); + rootViewTransitionNameCanceled = true; } popViewTransitionCancelableScope(null); break; @@ -3613,7 +3616,7 @@ function commitPassiveMountOnFiber( } if (isViewTransitionEligible) { - if (supportsMutation) { + if (supportsMutation && rootViewTransitionNameCanceled) { restoreRootViewTransitionName(finishedRoot.containerInfo); } } diff --git a/scripts/error-codes/codes.json b/scripts/error-codes/codes.json index d81f7489f99..3c64fcc4719 100644 --- a/scripts/error-codes/codes.json +++ b/scripts/error-codes/codes.json @@ -544,5 +544,6 @@ "556": "Expected prepareToHydrateHostActivityInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.", "557": "Expected to have a hydrated activity instance. This error is likely caused by a bug in React. Please file an issue.", "558": "Client rendering an Activity suspended it again. This is a bug in React.", - "559": "Expected to find a host node. This is a bug in React." + "559": "Expected to find a host node. This is a bug in React.", + "560": "Cannot use a startGestureTransition() with a comment node root." }