Skip to content

Commit 81dc31e

Browse files
committed
Mark the root as animating if any Portal mutates or resizes (#32772)
Portals and `<ViewTransition>` are tricky because they leave the React tree. You might think of a Portal's container conceptually as also being part of a React tree but that's not quite how they're modeled today. They're more like their own roots. So instead, of trying to find a conceptual place in the React tree we treat Portals as their own root. We have two ways of tracking whether an update to a ViewTransition boundary has occurred. Either a DOM mutation has happened within it, or a resize of a child has caused it to potentially relayout its parent. Normally that just follows the tree structure of React, but not when it's a Portal. When it's a Portal we don't know which DOM parent it might have affected. For all we know it's at the root (and in fact, in most cases that's where Portals go). With this PR we mark the root as having been affected by a mutation or resize. This means that the whole document will animate and we can't optimize away from it. This ensures that a mutation to the root of a Portal doesn't go unanimated with other things are animating such as its parent. You can regain this optimization by adding a `<ViewTransition>` boundary directly inside the Portal itself so it owns its own animation. If that DOM node is also absolutely positioned it doesn't leak. Conversely this also means that a mutation inside a Portal doesn't affect its React parent so it won't trigger its parent's animation if this was the only thing animating. That could be unfortunate if this container is actually inside the same React parent. However, because this would have been an update we would've marked it for "maybe animating" and updates can't only get their animations cancelled if the root is cancelled, in practice this will actually animate anyway. DiffTrain build for [95671b4](95671b4)
1 parent cb70b73 commit 81dc31e

34 files changed

+2014
-1738
lines changed

Diff for: compiled/facebook-www/REVISION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ef4bc8b4f91023afac437be9179beef350b32db3
1+
95671b4eb3ceb51278a2ba959667da04f0b09809

Diff for: compiled/facebook-www/REVISION_TRANSFORMS

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
ef4bc8b4f91023afac437be9179beef350b32db3
1+
95671b4eb3ceb51278a2ba959667da04f0b09809

Diff for: compiled/facebook-www/React-dev.classic.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1511,7 +1511,7 @@ __DEV__ &&
15111511
exports.useTransition = function () {
15121512
return resolveDispatcher().useTransition();
15131513
};
1514-
exports.version = "19.1.0-www-classic-ef4bc8b4-20250328";
1514+
exports.version = "19.2.0-www-classic-95671b4e-20250331";
15151515
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15161516
"function" ===
15171517
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

Diff for: compiled/facebook-www/React-dev.modern.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1511,7 +1511,7 @@ __DEV__ &&
15111511
exports.useTransition = function () {
15121512
return resolveDispatcher().useTransition();
15131513
};
1514-
exports.version = "19.1.0-www-modern-ef4bc8b4-20250328";
1514+
exports.version = "19.2.0-www-modern-95671b4e-20250331";
15151515
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
15161516
"function" ===
15171517
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

Diff for: compiled/facebook-www/React-prod.classic.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -624,4 +624,4 @@ exports.useSyncExternalStore = function (
624624
exports.useTransition = function () {
625625
return ReactSharedInternals.H.useTransition();
626626
};
627-
exports.version = "19.1.0-www-classic-ef4bc8b4-20250328";
627+
exports.version = "19.2.0-www-classic-95671b4e-20250331";

Diff for: compiled/facebook-www/React-prod.modern.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -624,4 +624,4 @@ exports.useSyncExternalStore = function (
624624
exports.useTransition = function () {
625625
return ReactSharedInternals.H.useTransition();
626626
};
627-
exports.version = "19.1.0-www-modern-ef4bc8b4-20250328";
627+
exports.version = "19.2.0-www-modern-95671b4e-20250331";

Diff for: compiled/facebook-www/React-profiling.classic.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ exports.useSyncExternalStore = function (
628628
exports.useTransition = function () {
629629
return ReactSharedInternals.H.useTransition();
630630
};
631-
exports.version = "19.1.0-www-classic-ef4bc8b4-20250328";
631+
exports.version = "19.2.0-www-classic-95671b4e-20250331";
632632
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
633633
"function" ===
634634
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

Diff for: compiled/facebook-www/React-profiling.modern.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ exports.useSyncExternalStore = function (
628628
exports.useTransition = function () {
629629
return ReactSharedInternals.H.useTransition();
630630
};
631-
exports.version = "19.1.0-www-modern-ef4bc8b4-20250328";
631+
exports.version = "19.2.0-www-modern-95671b4e-20250331";
632632
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
633633
"function" ===
634634
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

Diff for: compiled/facebook-www/ReactART-dev.classic.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -10293,6 +10293,12 @@ __DEV__ &&
1029310293
captureCommitPhaseError(finishedWork, finishedWork.return, error);
1029410294
}
1029510295
}
10296+
function pushMutationContext() {
10297+
if (!enableViewTransition) return !1;
10298+
var prev = viewTransitionMutationContext;
10299+
viewTransitionMutationContext = !1;
10300+
return prev;
10301+
}
1029610302
function trackHostMutation() {
1029710303
enableViewTransition && (viewTransitionMutationContext = !0);
1029810304
}
@@ -11601,8 +11607,10 @@ __DEV__ &&
1160111607
root.effectDuration += popNestedEffectDurations(flags);
1160211608
break;
1160311609
case 4:
11610+
flags = pushMutationContext();
1160411611
recursivelyTraverseMutationEffects(root, finishedWork, lanes);
1160511612
commitReconciliationEffects(finishedWork);
11613+
enableViewTransition && (viewTransitionMutationContext = flags);
1160611614
break;
1160711615
case 12:
1160811616
flags = pushNestedEffectDurations();
@@ -11757,10 +11765,7 @@ __DEV__ &&
1175711765
(offscreenSubtreeWasHidden ||
1175811766
null === current ||
1175911767
safelyDetachRef(current, current.return)),
11760-
enableViewTransition
11761-
? ((flags = viewTransitionMutationContext),
11762-
(viewTransitionMutationContext = !1))
11763-
: (flags = !1),
11768+
(flags = pushMutationContext()),
1176411769
recursivelyTraverseMutationEffects(root, finishedWork, lanes),
1176511770
commitReconciliationEffects(finishedWork),
1176611771
enableViewTransition &&
@@ -18200,10 +18205,10 @@ __DEV__ &&
1820018205
(function () {
1820118206
var internals = {
1820218207
bundleType: 1,
18203-
version: "19.1.0-www-classic-ef4bc8b4-20250328",
18208+
version: "19.2.0-www-classic-95671b4e-20250331",
1820418209
rendererPackageName: "react-art",
1820518210
currentDispatcherRef: ReactSharedInternals,
18206-
reconcilerVersion: "19.1.0-www-classic-ef4bc8b4-20250328"
18211+
reconcilerVersion: "19.2.0-www-classic-95671b4e-20250331"
1820718212
};
1820818213
internals.overrideHookState = overrideHookState;
1820918214
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -18237,7 +18242,7 @@ __DEV__ &&
1823718242
exports.Shape = Shape;
1823818243
exports.Surface = Surface;
1823918244
exports.Text = Text;
18240-
exports.version = "19.1.0-www-classic-ef4bc8b4-20250328";
18245+
exports.version = "19.2.0-www-classic-95671b4e-20250331";
1824118246
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1824218247
"function" ===
1824318248
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

Diff for: compiled/facebook-www/ReactART-dev.modern.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -10111,6 +10111,12 @@ __DEV__ &&
1011110111
captureCommitPhaseError(finishedWork, finishedWork.return, error);
1011210112
}
1011310113
}
10114+
function pushMutationContext() {
10115+
if (!enableViewTransition) return !1;
10116+
var prev = viewTransitionMutationContext;
10117+
viewTransitionMutationContext = !1;
10118+
return prev;
10119+
}
1011410120
function trackHostMutation() {
1011510121
enableViewTransition && (viewTransitionMutationContext = !0);
1011610122
}
@@ -11419,8 +11425,10 @@ __DEV__ &&
1141911425
root.effectDuration += popNestedEffectDurations(flags);
1142011426
break;
1142111427
case 4:
11428+
flags = pushMutationContext();
1142211429
recursivelyTraverseMutationEffects(root, finishedWork, lanes);
1142311430
commitReconciliationEffects(finishedWork);
11431+
enableViewTransition && (viewTransitionMutationContext = flags);
1142411432
break;
1142511433
case 12:
1142611434
flags = pushNestedEffectDurations();
@@ -11575,10 +11583,7 @@ __DEV__ &&
1157511583
(offscreenSubtreeWasHidden ||
1157611584
null === current ||
1157711585
safelyDetachRef(current, current.return)),
11578-
enableViewTransition
11579-
? ((flags = viewTransitionMutationContext),
11580-
(viewTransitionMutationContext = !1))
11581-
: (flags = !1),
11586+
(flags = pushMutationContext()),
1158211587
recursivelyTraverseMutationEffects(root, finishedWork, lanes),
1158311588
commitReconciliationEffects(finishedWork),
1158411589
enableViewTransition &&
@@ -17972,10 +17977,10 @@ __DEV__ &&
1797217977
(function () {
1797317978
var internals = {
1797417979
bundleType: 1,
17975-
version: "19.1.0-www-modern-ef4bc8b4-20250328",
17980+
version: "19.2.0-www-modern-95671b4e-20250331",
1797617981
rendererPackageName: "react-art",
1797717982
currentDispatcherRef: ReactSharedInternals,
17978-
reconcilerVersion: "19.1.0-www-modern-ef4bc8b4-20250328"
17983+
reconcilerVersion: "19.2.0-www-modern-95671b4e-20250331"
1797917984
};
1798017985
internals.overrideHookState = overrideHookState;
1798117986
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -18009,7 +18014,7 @@ __DEV__ &&
1800918014
exports.Shape = Shape;
1801018015
exports.Surface = Surface;
1801118016
exports.Text = Text;
18012-
exports.version = "19.1.0-www-modern-ef4bc8b4-20250328";
18017+
exports.version = "19.2.0-www-modern-95671b4e-20250331";
1801318018
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1801418019
"function" ===
1801518020
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)