From 33a135f0614d10d3ce9c2ca6ce11dd8bc2418996 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 6 Mar 2025 23:03:00 -0500 Subject: [PATCH] Cancel view transitions in fire-and-forget too --- .../src/client/ReactFiberConfigDOM.js | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 47d6a4cb24806..39d50d617c7d7 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -1550,6 +1550,21 @@ export function hasInstanceAffectedParent( return oldRect.height !== newRect.height || oldRect.width !== newRect.width; } +function cancelAllViewTransitionAnimations(ownerDocument: Document) { + // In Safari, we need to manually cancel all manually start animations + // or it'll block or interfer with future transitions. + const animations = ownerDocument.getAnimations(); + for (let i = 0; i < animations.length; i++) { + const anim = animations[i]; + const effect: KeyframeEffect = (anim.effect: any); + // $FlowFixMe + const pseudo: ?string = effect.pseudoElement; + if (pseudo != null && pseudo.startsWith('::view-transition')) { + anim.cancel(); + } + } +} + // How long to wait for new fonts to load before just committing anyway. // This freezes the screen. It needs to be short enough that it doesn't cause too much of // an issue when it's a new load and slow, yet long enough that you have a chance to load @@ -1640,6 +1655,7 @@ export function startViewTransition( } transition.ready.then(spawnedWorkCallback, spawnedWorkCallback); transition.finished.then(() => { + cancelAllViewTransitionAnimations(ownerDocument); // $FlowFixMe[prop-missing] if (ownerDocument.__reactViewTransition === transition) { // $FlowFixMe[prop-missing] @@ -1817,6 +1833,9 @@ export function startGestureTransition( } for (let i = 0; i < animations.length; i++) { const anim = animations[i]; + if (anim.playState !== 'running') { + continue; + } const effect: KeyframeEffect = (anim.effect: any); // $FlowFixMe const pseudoElement: ?string = effect.pseudoElement; @@ -1913,19 +1932,7 @@ export function startGestureTransition( : readyCallback; transition.ready.then(readyForAnimations, readyCallback); transition.finished.then(() => { - // In Safari, we need to manually cancel all manually start animations - // or it'll block future transitions. - const documentElement: Element = (ownerDocument.documentElement: any); - const animations = documentElement.getAnimations({subtree: true}); - for (let i = 0; i < animations.length; i++) { - const anim = animations[i]; - const effect: KeyframeEffect = (anim.effect: any); - // $FlowFixMe - const pseudo: ?string = effect.pseudoElement; - if (pseudo != null && pseudo.startsWith('::view-transition')) { - anim.cancel(); - } - } + cancelAllViewTransitionAnimations(ownerDocument); // $FlowFixMe[prop-missing] if (ownerDocument.__reactViewTransition === transition) { // $FlowFixMe[prop-missing]