Skip to content
/ lib-react Public
forked from facebook/react

Commit 65040f5

Browse files
committed
Add Transition Types (facebook#32105)
This adds an isomorphic API to add Transition Types, which represent the cause, to the current Transition. This is currently mainly for View Transitions but as a concept it's broader and we might expand it to more features and object types in the future. ```js import { unstable_addTransitionType as addTransitionType } from 'react'; startTransition(() => { addTransitionType('my-transition-type'); setState(...); }); ``` If multiple transitions get entangled this is additive and all Transition Types are collected. You can also add more than one type to a Transition (hence the `add` prefix). Transition Types are reset after each commit. Meaning that `<Suspense>` revealing after a `startTransition` does not get any View Transition types associated with it. Note that the scoping rules for this is a little "wrong" in this implementation. Ideally it would be scoped to the nearest outer `startTransition` and grouped with any `setState` inside of it. Including Actions. However, since we currently don't have AsyncContext on the client, it would be too easy to drop a Transition Type if there were no other `setState` in the same `await` task. Multiple Transitions are entangled together anyway right now as a result. So this just tracks a global of all pending Transition Types for the next Transition. An inherent tricky bit with this API is that you could update multiple roots. In that case it should ideally be associated with each root. Transition Tracing solves this by associating a Transition with any updates that are later collected but this suffers from the problem mentioned above. Therefore, I just associate Transition Types with one root - the first one to commit. Since the View Transitions across roots are sequential anyway it kind of makes sense that only one really is the cause and the other one is subsequent. Transition Types can be used to apply different animations based on what caused the Transition. You have three different ways to choose from for how to use them: ## CSS It integrates with [View Transition Types](https://www.w3.org/TR/css-view-transitions-2/#active-view-transition-pseudo-examples) so you can match different animations based on CSS scopes: ```css :root:active-view-transition-type(my-transition-type) { &::view-transition-...(...) { ... } } ``` This is kind of a PITA to write though and if you have a CSS library that provide View Transition Classes it's difficult to import those into these scopes. ## Class per Type This PR also adds an object-as-map form that can be passed to all `className` properties: ```js <ViewTransition className={{ 'my-navigation-type': 'hello', 'default': 'world', }}> ``` If multiple types match, then they're joined together. If no types match then the special `"default"` entry is used instead. If any type has the value `"none"` then that wins and the ViewTransition is disabled (not assigned a name). These can be combined with `enter`/`exit`/`update`/`layout`/`share` props to match based on kind of trigger and Transition Type. ```js <ViewTransition enter={{ 'navigation-back': 'enter-right', 'navigation-forward': 'enter-left', }} exit={{ 'navigation-back': 'exit-right', 'navigation-forward': 'exit-left', }}> ``` ## Events In addition, you can also observe the types in the View Transition Event callbacks as the second argument. That way you can pick different imperative Animations based on the cause. ```js <ViewTransition onUpdate={(inst, types) => { if (types.includes('navigation-back')) { ... } else if (types.includes('navigation-forward')) { ... } else { ... } }}> ``` ## Future In the future we might expose types to `useEffect` for more general purpose usage. This would also allow non-View Transition based Animations such as existing libraries to use this same feature to coordinate the same concept. We might also allow richer objects to be passed along here. Only the strings would apply to View Transitions but the imperative code and effects could do something else with them. DiffTrain build for [028c8e6](facebook@028c8e6)
1 parent d969bf5 commit 65040f5

34 files changed

+92
-90
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
829401dc173d79994a3401fce24084670f55fb5c
1+
028c8e6cf5ce2a87147a7e03e503ce94c7a7a0cf
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
829401dc173d79994a3401fce24084670f55fb5c
1+
028c8e6cf5ce2a87147a7e03e503ce94c7a7a0cf

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,7 @@ __DEV__ &&
12091209
A: null,
12101210
T: null,
12111211
S: null,
1212+
V: null,
12121213
actQueue: null,
12131214
isBatchingLegacy: !1,
12141215
didScheduleLegacyUpdate: !1,
@@ -1956,7 +1957,7 @@ __DEV__ &&
19561957
exports.useTransition = function () {
19571958
return resolveDispatcher().useTransition();
19581959
};
1959-
exports.version = "19.1.0-www-classic-829401dc-20250117";
1960+
exports.version = "19.1.0-www-classic-028c8e6c-20250121";
19601961
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
19611962
"function" ===
19621963
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,7 @@ __DEV__ &&
12091209
A: null,
12101210
T: null,
12111211
S: null,
1212+
V: null,
12121213
actQueue: null,
12131214
isBatchingLegacy: !1,
12141215
didScheduleLegacyUpdate: !1,
@@ -1956,7 +1957,7 @@ __DEV__ &&
19561957
exports.useTransition = function () {
19571958
return resolveDispatcher().useTransition();
19581959
};
1959-
exports.version = "19.1.0-www-modern-829401dc-20250117";
1960+
exports.version = "19.1.0-www-modern-028c8e6c-20250121";
19601961
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
19611962
"function" ===
19621963
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pureComponentPrototype.constructor = PureComponent;
9090
assign(pureComponentPrototype, Component.prototype);
9191
pureComponentPrototype.isPureReactComponent = !0;
9292
var isArrayImpl = Array.isArray,
93-
ReactSharedInternals = { H: null, A: null, T: null, S: null },
93+
ReactSharedInternals = { H: null, A: null, T: null, S: null, V: null },
9494
hasOwnProperty = Object.prototype.hasOwnProperty;
9595
function ReactElement(type, key, self, source, owner, props) {
9696
self = props.ref;
@@ -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-829401dc-20250117";
633+
exports.version = "19.1.0-www-classic-028c8e6c-20250121";

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pureComponentPrototype.constructor = PureComponent;
9090
assign(pureComponentPrototype, Component.prototype);
9191
pureComponentPrototype.isPureReactComponent = !0;
9292
var isArrayImpl = Array.isArray,
93-
ReactSharedInternals = { H: null, A: null, T: null, S: null },
93+
ReactSharedInternals = { H: null, A: null, T: null, S: null, V: null },
9494
hasOwnProperty = Object.prototype.hasOwnProperty;
9595
function ReactElement(type, key, self, source, owner, props) {
9696
self = props.ref;
@@ -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-829401dc-20250117";
633+
exports.version = "19.1.0-www-modern-028c8e6c-20250121";

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pureComponentPrototype.constructor = PureComponent;
9494
assign(pureComponentPrototype, Component.prototype);
9595
pureComponentPrototype.isPureReactComponent = !0;
9696
var isArrayImpl = Array.isArray,
97-
ReactSharedInternals = { H: null, A: null, T: null, S: null },
97+
ReactSharedInternals = { H: null, A: null, T: null, S: null, V: null },
9898
hasOwnProperty = Object.prototype.hasOwnProperty;
9999
function ReactElement(type, key, self, source, owner, props) {
100100
self = props.ref;
@@ -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-829401dc-20250117";
637+
exports.version = "19.1.0-www-classic-028c8e6c-20250121";
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pureComponentPrototype.constructor = PureComponent;
9494
assign(pureComponentPrototype, Component.prototype);
9595
pureComponentPrototype.isPureReactComponent = !0;
9696
var isArrayImpl = Array.isArray,
97-
ReactSharedInternals = { H: null, A: null, T: null, S: null },
97+
ReactSharedInternals = { H: null, A: null, T: null, S: null, V: null },
9898
hasOwnProperty = Object.prototype.hasOwnProperty;
9999
function ReactElement(type, key, self, source, owner, props) {
100100
self = props.ref;
@@ -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-829401dc-20250117";
637+
exports.version = "19.1.0-www-modern-028c8e6c-20250121";
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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16950,10 +16950,10 @@ __DEV__ &&
1695016950
(function () {
1695116951
var internals = {
1695216952
bundleType: 1,
16953-
version: "19.1.0-www-classic-829401dc-20250117",
16953+
version: "19.1.0-www-classic-028c8e6c-20250121",
1695416954
rendererPackageName: "react-art",
1695516955
currentDispatcherRef: ReactSharedInternals,
16956-
reconcilerVersion: "19.1.0-www-classic-829401dc-20250117"
16956+
reconcilerVersion: "19.1.0-www-classic-028c8e6c-20250121"
1695716957
};
1695816958
internals.overrideHookState = overrideHookState;
1695916959
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16987,7 +16987,7 @@ __DEV__ &&
1698716987
exports.Shape = Shape;
1698816988
exports.Surface = Surface;
1698916989
exports.Text = Text;
16990-
exports.version = "19.1.0-www-classic-829401dc-20250117";
16990+
exports.version = "19.1.0-www-classic-028c8e6c-20250121";
1699116991
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1699216992
"function" ===
1699316993
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16722,10 +16722,10 @@ __DEV__ &&
1672216722
(function () {
1672316723
var internals = {
1672416724
bundleType: 1,
16725-
version: "19.1.0-www-modern-829401dc-20250117",
16725+
version: "19.1.0-www-modern-028c8e6c-20250121",
1672616726
rendererPackageName: "react-art",
1672716727
currentDispatcherRef: ReactSharedInternals,
16728-
reconcilerVersion: "19.1.0-www-modern-829401dc-20250117"
16728+
reconcilerVersion: "19.1.0-www-modern-028c8e6c-20250121"
1672916729
};
1673016730
internals.overrideHookState = overrideHookState;
1673116731
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
@@ -16759,7 +16759,7 @@ __DEV__ &&
1675916759
exports.Shape = Shape;
1676016760
exports.Surface = Surface;
1676116761
exports.Text = Text;
16762-
exports.version = "19.1.0-www-modern-829401dc-20250117";
16762+
exports.version = "19.1.0-www-modern-028c8e6c-20250121";
1676316763
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
1676416764
"function" ===
1676516765
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&

0 commit comments

Comments
 (0)