@samitouri / QOS-React / commits / 38127b2815

[Fiber] Support only View Transitions v2 (#31996)

Stacked on #31975. We're going to recommend that the primary way you style a View Transition is using a View Transition Class (and/or Type). These are only available in the View Transitions v2 spec. When they're not available it's better to fallback to just not animating instead of animating with the wrong styling rules applied. This is already widely supported in Chrome and Safari 18.2. Safari 18.2 usage is still somewhat low but it's rolling out quickly as we speak. A way to detect this is by just passing the object form to `startViewTransition` which throws if it's an earlier version. The object form is required for `types` but luckily classes rolled out at the same time. Therefore we're only indirectly detecting class support. This means that in practice Safari 18.0 and 18.1 won't animate. We could try to only apply the feature detection if you're actually using classes or types, but that would create an unfortunate ecosystem burden to try to support names. It also leads to flaky effects when only some animations work. Better to just disable them all. Firefox has yet to ship anything. We'll have to look out for how the feature detection happens there and if they roll things out in different order but if you ship late, you deal with web compat as the ball lies.

Sebastian Markbåge committed Jan 8, 2025 at 13:22 UTC 38127b281567d43972b7fb44c3fcb0d1806e7c10
1 file changed +20 -11
packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
+20 -11
@@ -1209,19 +1209,28 @@ export function startViewTransition(
1209 rootContainer.nodeType === DOCUMENT_NODE
1210 ? rootContainer
1211 : rootContainer.ownerDocument;
1212 - // $FlowFixMe[prop-missing]
1213 - if (typeof ownerDocument.startViewTransition !== 'function') {
1212 + try {
1213 + // $FlowFixMe[prop-missing]
1214 + const transition = ownerDocument.startViewTransition({
1215 + update() {
1216 + mutationCallback();
1217 + // TODO: Wait for fonts.
1218 + afterMutationCallback();
1219 + },
1220 + types: null, // TODO: Provide types.
1221 + });
1222 + transition.ready.then(layoutCallback, layoutCallback);
1223 + transition.finished.then(passiveCallback);
1224 + return true;
1225 + } catch (x) {
1226 + // We use the error as feature detection.
1227 + // The only thing that should throw is if startViewTransition is missing
1228 + // or if it doesn't accept the object form. Other errors are async.
1229 + // I.e. it's before the View Transitions v2 spec. We only support View
1230 + // Transitions v2 otherwise we fallback to not animating to ensure that
1231 + // we're not animating with the wrong animation mapped.
1232 return false;
1233 }
1216 - // $FlowFixMe[incompatible-use]
1217 - const transition = ownerDocument.startViewTransition(() => {
1218 - mutationCallback();
1219 - // TODO: Wait for fonts.
1220 - afterMutationCallback();
1221 - });
1222 - transition.ready.then(layoutCallback, layoutCallback);
1223 - transition.finished.then(passiveCallback);
1224 - return true;
1234 }
1235
1236 export function clearContainer(container: Container): void {