Skip to content

Commit e0c99c4

Browse files
authored
Rename <ViewTransition className="..."> to <ViewTransition default="..."> (#32734)
It was always confusing that this is not a CSS class but a view-transition-class. The `className` sticks out a bit among its siblings `enter`, `exit`, `update` and `share`. The idea is that the most specific definition override is the class name that gets applied and this prop is really just the fallback, catch-all or "any" that is applied if you didn't specify a more specific one. It has also since evolved not just to take a string but also a map of Transition Type to strings. The "class" is really the type of the value. We could add a suffix to all of them like `defaultClass`, `enterClass`, `exitClass`, `updateClass` and `shareClass`. However, this doesn't necessarily make sense with the mapping of Transition Type to string. It also makes it a bit too DOM centric. In React Native this might still be called a "class" but it might be represented by an object definition. We might even allow some kind of inline style form for the DOM too. Really this is about picking which "animation" that runs which can be a string or instance. "Animation" is too broad because there's also a concept of a CSS Animation and these are really sets of CSS animations (group, image-pair, old, new). It could maybe be `defaultTransition`, `enterTransition`, etc but that seems unnecessarily repetitive and still doesn't say anything about it being a class. We also already have the name "default" in the map of Transition Types. In fact you can now specify a default for default: ``` <ViewTransition default={{"navigation-back": "slide-out", "default": "fade-in"}}> ``` One thing I don't like about the name `"default"` is that it might be common to just apply a named class that does it matching to enter/exit/update in the CSS selectors (such as the `:only-child` rule) instead of doing that mapping to each one using React. In that can you end up specifying only `default={...}` a lot and then what is it the "default" for? It's more like "all". I think it's likely that you end up with either "default" or the specific forms instead of both at once.
1 parent a5297ec commit e0c99c4

File tree

5 files changed

+40
-25
lines changed

5 files changed

+40
-25
lines changed

fixtures/view-transition/src/components/Page.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const b = (
3333
function Component() {
3434
return (
3535
<ViewTransition
36-
className={
36+
default={
3737
transitions['enter-slide-right'] + ' ' + transitions['exit-slide-left']
3838
}>
3939
<p className="roboto-font">Slide In from Left, Slide Out to Right</p>
@@ -97,17 +97,17 @@ export default function Page({url, navigate}) {
9797
}}>
9898
{url === '/?b' ? 'Goto A' : 'Goto B'}
9999
</button>
100-
<ViewTransition className="none">
100+
<ViewTransition default="none">
101101
<div>
102102
<ViewTransition>
103103
<div>
104-
<ViewTransition className={transitions['slide-on-nav']}>
104+
<ViewTransition default={transitions['slide-on-nav']}>
105105
<h1>{!show ? 'A' : 'B' + counter}</h1>
106106
</ViewTransition>
107107
</div>
108108
</ViewTransition>
109109
<ViewTransition
110-
className={{
110+
default={{
111111
'navigation-back': transitions['slide-right'],
112112
'navigation-forward': transitions['slide-left'],
113113
}}>

packages/react-reconciler/src/ReactFiberApplyGesture.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ function trackDeletedPairViewTransitions(deletion: Fiber): void {
151151
// and can stop searching (size reaches zero).
152152
pairs.delete(name);
153153
const className: ?string = getViewTransitionClassName(
154-
props.className,
154+
props.default,
155155
props.share,
156156
);
157157
if (className !== 'none') {
@@ -196,7 +196,7 @@ function trackEnterViewTransitions(deletion: Fiber): void {
196196
? appearingViewTransitions.get(name)
197197
: undefined;
198198
const className: ?string = getViewTransitionClassName(
199-
props.className,
199+
props.default,
200200
pair !== undefined ? props.share : props.enter,
201201
);
202202
if (className !== 'none') {
@@ -259,7 +259,7 @@ function applyAppearingPairViewTransition(child: Fiber): void {
259259
// Note that this class name that doesn't actually really matter because the
260260
// "new" side will be the one that wins in practice.
261261
const className: ?string = getViewTransitionClassName(
262-
props.className,
262+
props.default,
263263
props.share,
264264
);
265265
if (className !== 'none') {
@@ -282,7 +282,7 @@ function applyExitViewTransition(placement: Fiber): void {
282282
const props: ViewTransitionProps = placement.memoizedProps;
283283
const name = getViewTransitionName(props, state);
284284
const className: ?string = getViewTransitionClassName(
285-
props.className,
285+
props.default,
286286
// Note that just because we don't have a pair yet doesn't mean we won't find one
287287
// later. However, that doesn't matter because if we do the class name that wins
288288
// is the one applied by the "new" side anyway.
@@ -307,7 +307,7 @@ function applyNestedViewTransition(child: Fiber): void {
307307
const props: ViewTransitionProps = child.memoizedProps;
308308
const name = getViewTransitionName(props, state);
309309
const className: ?string = getViewTransitionClassName(
310-
props.className,
310+
props.default,
311311
props.update,
312312
);
313313
if (className !== 'none') {
@@ -336,7 +336,7 @@ function applyUpdateViewTransition(current: Fiber, finishedWork: Fiber): void {
336336
// want the props from "current" since that's the class that would've won if
337337
// it was the normal direction. To preserve the same effect in either direction.
338338
const className: ?string = getViewTransitionClassName(
339-
newProps.className,
339+
newProps.default,
340340
newProps.update,
341341
);
342342
if (className === 'none') {

packages/react-reconciler/src/ReactFiberBeginWork.js

+21
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ export let didWarnAboutReassigningProps: boolean;
322322
let didWarnAboutRevealOrder;
323323
let didWarnAboutTailOptions;
324324
let didWarnAboutDefaultPropsOnFunctionComponent;
325+
let didWarnAboutClassNameOnViewTransition;
325326

326327
if (__DEV__) {
327328
didWarnAboutBadClass = ({}: {[string]: boolean});
@@ -332,6 +333,7 @@ if (__DEV__) {
332333
didWarnAboutRevealOrder = ({}: {[empty]: boolean});
333334
didWarnAboutTailOptions = ({}: {[string]: boolean});
334335
didWarnAboutDefaultPropsOnFunctionComponent = ({}: {[string]: boolean});
336+
didWarnAboutClassNameOnViewTransition = ({}: {[string]: boolean});
335337
}
336338

337339
export function reconcileChildren(
@@ -3295,6 +3297,25 @@ function updateViewTransition(
32953297
pushMaterializedTreeId(workInProgress);
32963298
}
32973299
}
3300+
if (__DEV__) {
3301+
// $FlowFixMe[prop-missing]
3302+
if (pendingProps.className !== undefined) {
3303+
const example =
3304+
typeof pendingProps.className === 'string'
3305+
? JSON.stringify(pendingProps.className)
3306+
: '{...}';
3307+
if (!didWarnAboutClassNameOnViewTransition[example]) {
3308+
didWarnAboutClassNameOnViewTransition[example] = true;
3309+
console.error(
3310+
'<ViewTransition> doesn\'t accept a "className" prop. It has been renamed to "default".\n' +
3311+
'- <ViewTransition className=%s>\n' +
3312+
'+ <ViewTransition default=%s>',
3313+
example,
3314+
example,
3315+
);
3316+
}
3317+
}
3318+
}
32983319
if (current !== null && current.memoizedProps.name !== pendingProps.name) {
32993320
// If the name changes, we schedule a ref effect to create a new ref instance.
33003321
workInProgress.flags |= Ref | RefStatic;

packages/react-reconciler/src/ReactFiberCommitViewTransitions.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ function commitAppearingPairViewTransitions(placement: Fiber): void {
228228
}
229229
const name = props.name;
230230
const className: ?string = getViewTransitionClassName(
231-
props.className,
231+
props.default,
232232
props.share,
233233
);
234234
if (className !== 'none') {
@@ -267,7 +267,7 @@ export function commitEnterViewTransitions(
267267
const props: ViewTransitionProps = placement.memoizedProps;
268268
const name = getViewTransitionName(props, state);
269269
const className: ?string = getViewTransitionClassName(
270-
props.className,
270+
props.default,
271271
state.paired ? props.share : props.enter,
272272
);
273273
if (className !== 'none') {
@@ -337,7 +337,7 @@ function commitDeletedPairViewTransitions(deletion: Fiber): void {
337337
const pair = pairs.get(name);
338338
if (pair !== undefined) {
339339
const className: ?string = getViewTransitionClassName(
340-
props.className,
340+
props.default,
341341
props.share,
342342
);
343343
if (className !== 'none') {
@@ -389,7 +389,7 @@ export function commitExitViewTransitions(deletion: Fiber): void {
389389
? appearingViewTransitions.get(name)
390390
: undefined;
391391
const className: ?string = getViewTransitionClassName(
392-
props.className,
392+
props.default,
393393
pair !== undefined ? props.share : props.exit,
394394
);
395395
if (className !== 'none') {
@@ -470,7 +470,7 @@ export function commitBeforeUpdateViewTransition(
470470
// a layout only change, then the "foo" class will be applied even though
471471
// it was not actually an update. Which is a bug.
472472
const className: ?string = getViewTransitionClassName(
473-
newProps.className,
473+
newProps.default,
474474
newProps.update,
475475
);
476476
if (className === 'none') {
@@ -495,7 +495,7 @@ export function commitNestedViewTransitions(changedParent: Fiber): void {
495495
const props: ViewTransitionProps = child.memoizedProps;
496496
const name = getViewTransitionName(props, child.stateNode);
497497
const className: ?string = getViewTransitionClassName(
498-
props.className,
498+
props.default,
499499
props.update,
500500
);
501501
if (className !== 'none') {
@@ -735,7 +735,7 @@ export function measureUpdateViewTransition(
735735
const oldName = getViewTransitionName(oldFiber.memoizedProps, state);
736736
// Whether it ends up having been updated or relayout we apply the update class name.
737737
const className: ?string = getViewTransitionClassName(
738-
props.className,
738+
props.default,
739739
props.update,
740740
);
741741
if (className === 'none') {
@@ -787,7 +787,7 @@ export function measureNestedViewTransitions(
787787
const state: ViewTransitionState = child.stateNode;
788788
const name = getViewTransitionName(props, state);
789789
const className: ?string = getViewTransitionClassName(
790-
props.className,
790+
props.default,
791791
props.update,
792792
);
793793
let previousMeasurements: null | Array<InstanceMeasurement>;

packages/react-reconciler/src/ReactFiberViewTransitionComponent.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export type ViewTransitionClass = 'none' | string | ViewTransitionClassPerType;
2929
export type ViewTransitionProps = {
3030
name?: string,
3131
children?: ReactNodeList,
32-
className?: ViewTransitionClass,
32+
default?: ViewTransitionClass,
3333
enter?: ViewTransitionClass,
3434
exit?: ViewTransitionClass,
3535
share?: ViewTransitionClass,
@@ -129,11 +129,5 @@ export function getViewTransitionClassName(
129129
if (eventClassName == null) {
130130
return className;
131131
}
132-
if (eventClassName === 'none') {
133-
return eventClassName;
134-
}
135-
if (className != null && className !== 'none') {
136-
return className + ' ' + eventClassName;
137-
}
138132
return eventClassName;
139133
}

0 commit comments

Comments
 (0)