Skip to content

Commit 8387e73

Browse files
committed
View Transition Refs (facebook#32038)
This adds refs to View Transition that can resolve to an instance of: ```js type ViewTransitionRef = { name: string, group: Animatable, imagePair: Animatable, old: Animatable, new: Animatable, } ``` Animatable is a type that has `animate(keyframes, options)` and `getAnimations()` on it. It's the interface that exists on Element that lets you start animations on it. These ones are like that but for the four pseudo-elements created by the view transition. If a name changes, then a new ref is created. That way if you hold onto a ref during an exit animation spawned by the name change, you can keep calling functions on it. It will keep referring to the old name rather than the new name. This allows imperative control over the animations instead of using CSS for this. ```js const viewTransition = ref.current; const groupAnimation = viewTransition.group.animate(keyframes, options); const imagePairAnimation = viewTransition.imagePair.animate(keyframes, options); const oldAnimation = viewTransition.old.animate(keyframes, options); const newAnimation = viewTransition.new.animate(keyframes, options); ``` The downside of using this API is that it doesn't work with SSR so for SSR rendered animations they'll fallback to the CSS. You could use this for progressive enhancement though. Note: In this PR the ref only controls one DOM node child but there can be more than one DOM node in the ViewTransition fragment and they are just left to their defaults. We could try something like making the `animate()` function apply to multiple children but that could lead to some weird consequences and the return value would be difficult to merge. We could try to maintain an array of Animatable that updates with how ever many things are currently animating but that makes the API more complicated to use for the simple case. Conceptually this should be like a fragment so we would ideally combine the multiple children into a single isolate if we could. Maybe one day the same name could be applied to multiple children to create a single isolate. For now I think I'll just leave it like this and you're really expect to just use it with one DOM node. If you have more than one they just get the default animations from CSS. Using this is a little tricky due timing. In this fixture I just use a layout effect plus rAF to get into the right timing after the startViewTransition is ready. In the future I'll add an event that fires when View Transitions heuristics fire with the right timing. DiffTrain build for [0bf1f39](facebook@0bf1f39)
1 parent edc0a3a commit 8387e73

34 files changed

+322
-358
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
f2813ee33d37e20029c6698f34946d7f08eb7a95
1+
0bf1f39ec6906c666011c0c57aa56aa34a262daf
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
f2813ee33d37e20029c6698f34946d7f08eb7a95
1+
0bf1f39ec6906c666011c0c57aa56aa34a262daf

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1944,7 +1944,7 @@ __DEV__ &&
19441944
exports.useTransition = function () {
19451945
return resolveDispatcher().useTransition();
19461946
};
1947-
exports.version = "19.1.0-www-classic-f2813ee3-20250109";
1947+
exports.version = "19.1.0-www-classic-0bf1f39e-20250110";
19481948
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
19491949
"function" ===
19501950
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1944,7 +1944,7 @@ __DEV__ &&
19441944
exports.useTransition = function () {
19451945
return resolveDispatcher().useTransition();
19461946
};
1947-
exports.version = "19.1.0-www-modern-f2813ee3-20250109";
1947+
exports.version = "19.1.0-www-modern-0bf1f39e-20250110";
19481948
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
19491949
"function" ===
19501950
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,4 +630,4 @@ exports.useSyncExternalStore = function (
630630
exports.useTransition = function () {
631631
return ReactSharedInternals.H.useTransition();
632632
};
633-
exports.version = "19.1.0-www-classic-f2813ee3-20250109";
633+
exports.version = "19.1.0-www-classic-0bf1f39e-20250110";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,4 +630,4 @@ exports.useSyncExternalStore = function (
630630
exports.useTransition = function () {
631631
return ReactSharedInternals.H.useTransition();
632632
};
633-
exports.version = "19.1.0-www-modern-f2813ee3-20250109";
633+
exports.version = "19.1.0-www-modern-0bf1f39e-20250110";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ exports.useSyncExternalStore = function (
634634
exports.useTransition = function () {
635635
return ReactSharedInternals.H.useTransition();
636636
};
637-
exports.version = "19.1.0-www-classic-f2813ee3-20250109";
637+
exports.version = "19.1.0-www-classic-0bf1f39e-20250110";
638638
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
639639
"function" ===
640640
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ exports.useSyncExternalStore = function (
634634
exports.useTransition = function () {
635635
return ReactSharedInternals.H.useTransition();
636636
};
637-
exports.version = "19.1.0-www-modern-f2813ee3-20250109";
637+
exports.version = "19.1.0-www-modern-0bf1f39e-20250110";
638638
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
639639
"function" ===
640640
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9919,17 +9919,15 @@ __DEV__ &&
99199919
function commitAttachRef(finishedWork) {
99209920
var ref = finishedWork.ref;
99219921
if (null !== ref) {
9922-
var instance = finishedWork.stateNode;
99239922
switch (finishedWork.tag) {
99249923
case 26:
99259924
case 27:
99269925
case 5:
9927-
var instanceToUse = instance;
9926+
var instanceToUse = finishedWork.stateNode;
99289927
break;
99299928
default:
9930-
instanceToUse = instance;
9929+
instanceToUse = finishedWork.stateNode;
99319930
}
9932-
21 === finishedWork.tag && (instanceToUse = instance);
99339931
if ("function" === typeof ref)
99349932
if (shouldProfile(finishedWork))
99359933
try {
@@ -16947,10 +16945,10 @@ __DEV__ &&
1694716945
(function () {
1694816946
var internals = {
1694916947
bundleType: 1,
16950-
version: "19.1.0-www-classic-f2813ee3-20250109",
16948+
version: "19.1.0-www-classic-0bf1f39e-20250110",
1695116949
rendererPackageName: "react-art",
1695216950
currentDispatcherRef: ReactSharedInternals,
16953-
reconcilerVersion: "19.1.0-www-classic-f2813ee3-20250109"
16951+
reconcilerVersion: "19.1.0-www-classic-0bf1f39e-20250110"
1695416952
};
1695516953
internals.overrideHookState = overrideHookState;
1695616954
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16984,7 +16982,7 @@ __DEV__ &&
1698416982
exports.Shape = Shape;
1698516983
exports.Surface = Surface;
1698616984
exports.Text = Text;
16987-
exports.version = "19.1.0-www-classic-f2813ee3-20250109";
16985+
exports.version = "19.1.0-www-classic-0bf1f39e-20250110";
1698816986
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1698916987
"function" ===
1699016988
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

compiled/facebook-www/ReactART-dev.modern.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9737,17 +9737,15 @@ __DEV__ &&
97379737
function commitAttachRef(finishedWork) {
97389738
var ref = finishedWork.ref;
97399739
if (null !== ref) {
9740-
var instance = finishedWork.stateNode;
97419740
switch (finishedWork.tag) {
97429741
case 26:
97439742
case 27:
97449743
case 5:
9745-
var instanceToUse = instance;
9744+
var instanceToUse = finishedWork.stateNode;
97469745
break;
97479746
default:
9748-
instanceToUse = instance;
9747+
instanceToUse = finishedWork.stateNode;
97499748
}
9750-
21 === finishedWork.tag && (instanceToUse = instance);
97519749
if ("function" === typeof ref)
97529750
if (shouldProfile(finishedWork))
97539751
try {
@@ -16719,10 +16717,10 @@ __DEV__ &&
1671916717
(function () {
1672016718
var internals = {
1672116719
bundleType: 1,
16722-
version: "19.1.0-www-modern-f2813ee3-20250109",
16720+
version: "19.1.0-www-modern-0bf1f39e-20250110",
1672316721
rendererPackageName: "react-art",
1672416722
currentDispatcherRef: ReactSharedInternals,
16725-
reconcilerVersion: "19.1.0-www-modern-f2813ee3-20250109"
16723+
reconcilerVersion: "19.1.0-www-modern-0bf1f39e-20250110"
1672616724
};
1672716725
internals.overrideHookState = overrideHookState;
1672816726
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16756,7 +16754,7 @@ __DEV__ &&
1675616754
exports.Shape = Shape;
1675716755
exports.Surface = Surface;
1675816756
exports.Text = Text;
16759-
exports.version = "19.1.0-www-modern-f2813ee3-20250109";
16757+
exports.version = "19.1.0-www-modern-0bf1f39e-20250110";
1676016758
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1676116759
"function" ===
1676216760
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)