@@ -661,12 +661,21 @@ function commitAppearingPairViewTransitions(placement: Fiber): void {
661
661
// We found a new appearing view transition with the same name as this deletion.
662
662
// We'll transition between them.
663
663
viewTransitionHostInstanceIdx = 0 ;
664
- applyViewTransitionToHostInstances (
664
+ const inViewport = applyViewTransitionToHostInstances (
665
665
child . child ,
666
666
props . name ,
667
667
null ,
668
668
false ,
669
669
) ;
670
+ if ( ! inViewport ) {
671
+ // This boundary is exiting within the viewport but is going to leave the viewport.
672
+ // Instead, we treat this as an exit of the previous entry by reverting the new name.
673
+ // Ideally we could undo the old transition but it's now too late. It's also on its
674
+ // on snapshot. We have know was for it to paint onto the original group.
675
+ // TODO: This will lead to things unexpectedly having exit animations that normally
676
+ // wouldn't happen. Consider if we should just let this fly off the screen instead.
677
+ restoreViewTransitionOnHostInstances ( child . child , false ) ;
678
+ }
670
679
}
671
680
}
672
681
commitAppearingPairViewTransitions ( child ) ;
@@ -733,13 +742,25 @@ function commitDeletedPairViewTransitions(
733
742
if ( name != null && name !== 'auto' ) {
734
743
const pair = appearingViewTransitions . get ( name ) ;
735
744
if ( pair !== undefined ) {
736
- const oldinstance : ViewTransitionInstance = child . stateNode ;
737
- const newInstance : ViewTransitionInstance = pair ;
738
- newInstance . paired = oldinstance ;
739
745
// We found a new appearing view transition with the same name as this deletion.
740
- // We'll transition between them.
741
746
viewTransitionHostInstanceIdx = 0 ;
742
- applyViewTransitionToHostInstances ( child . child , name , null , false ) ;
747
+ const inViewport = applyViewTransitionToHostInstances (
748
+ child . child ,
749
+ name ,
750
+ null ,
751
+ false ,
752
+ ) ;
753
+ if ( ! inViewport ) {
754
+ // This boundary is not in the viewport so we won't treat it as a matched pair.
755
+ // Revert the transition names. This avoids it flying onto the screen which can
756
+ // be disruptive and doesn't really preserve any continuity anyway.
757
+ restoreViewTransitionOnHostInstances ( child . child , false ) ;
758
+ } else {
759
+ // We'll transition between them.
760
+ const oldinstance : ViewTransitionInstance = child . stateNode ;
761
+ const newInstance : ViewTransitionInstance = pair ;
762
+ newInstance . paired = oldinstance ;
763
+ }
743
764
// Delete the entry so that we know when we've found all of them
744
765
// and can stop searching (size reaches zero).
745
766
appearingViewTransitions . delete ( name ) ;
0 commit comments