@samitouri / QOS-React-1 / commits / 08064ea671

[Fizz] Make ViewTransition enter/exit/share null the same as none (#33331)

I believe that these mean the same thing. We don't have to emit the attribute if it's `none` for these cases because if there is no matching scenario we won't apply the animation in this case. The only case where we have to emit `none` in the attribute is for `vt-update` because those can block updates from propagating upwards.

Sebastian Markbåge committed May 22, 2025 at 10:21 UTC 08064ea6713ff55730c5d4f50b733891ebe0e875
1 file changed +11 -17
packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js
+11 -17
@@ -759,10 +759,9 @@ const SUBTREE_SCOPE = ~(ENTER_SCOPE | EXIT_SCOPE);
759
760 type ViewTransitionContext = {
761 update: 'none' | 'auto' | string,
762 - // null here means that this case can never trigger. Not "auto" like it does in props.
763 - enter: null | 'none' | 'auto' | string,
764 - exit: null | 'none' | 'auto' | string,
765 - share: null | 'none' | 'auto' | string,
762 + enter: 'none' | 'auto' | string,
763 + exit: 'none' | 'auto' | string,
764 + share: 'none' | 'auto' | string,
765 name: 'auto' | string,
766 autoName: string, // a name that can be used if an explicit one is not defined.
767 nameIdx: number, // keeps track of how many duplicates of this name we've emitted.
@@ -917,8 +916,8 @@ function getSuspenseViewTransition(
916 // we would've used (the parent ViewTransition name or auto-assign one).
917 const viewTransition: ViewTransitionContext = {
918 update: parentViewTransition.update, // For deep updates.
920 - enter: null,
921 - exit: null,
919 + enter: 'none',
920 + exit: 'none',
921 share: parentViewTransition.update, // For exit or enter of reveals.
922 name: parentViewTransition.autoName,
923 autoName: parentViewTransition.autoName,
@@ -989,13 +988,8 @@ export function getViewTransitionFormatContext(
988 share = parentViewTransition.share;
989 } else {
990 name = 'auto';
992 - share = null; // share is only relevant if there's an explicit name
991 + share = 'none'; // share is only relevant if there's an explicit name
992 }
994 - } else if (share === 'none') {
995 - // I believe if share is disabled, it means the same thing as if it doesn't
996 - // exit because enter/exit will take precedence and if it's deeply nested
997 - // it just animates along whatever the parent does when disabled.
998 - share = null;
993 } else {
994 if (share == null) {
995 share = 'auto';
@@ -1008,12 +1002,12 @@ export function getViewTransitionFormatContext(
1002 }
1003 }
1004 if (!(parentContext.tagScope & EXIT_SCOPE)) {
1011 - exit = null; // exit is only relevant for the first ViewTransition inside fallback
1005 + exit = 'none'; // exit is only relevant for the first ViewTransition inside fallback
1006 } else {
1007 resumableState.instructions |= NeedUpgradeToViewTransitions;
1008 }
1009 if (!(parentContext.tagScope & ENTER_SCOPE)) {
1016 - enter = null; // enter is only relevant for the first ViewTransition inside content
1010 + enter = 'none'; // enter is only relevant for the first ViewTransition inside content
1011 } else {
1012 resumableState.instructions |= NeedUpgradeToViewTransitions;
1013 }
@@ -1125,13 +1119,13 @@ function pushViewTransitionAttributes(
1119 viewTransition.nameIdx++;
1120 }
1121 pushStringAttribute(target, 'vt-update', viewTransition.update);
1128 - if (viewTransition.enter !== null) {
1122 + if (viewTransition.enter !== 'none') {
1123 pushStringAttribute(target, 'vt-enter', viewTransition.enter);
1124 }
1131 - if (viewTransition.exit !== null) {
1125 + if (viewTransition.exit !== 'none') {
1126 pushStringAttribute(target, 'vt-exit', viewTransition.exit);
1127 }
1134 - if (viewTransition.share !== null) {
1128 + if (viewTransition.share !== 'none') {
1129 pushStringAttribute(target, 'vt-share', viewTransition.share);
1130 }
1131 }