Skip to content

Commit 8e5254d

Browse files
committed
Allow passing an object-as-map for class names to match class based on type
This is more convenient than the CSS form.
1 parent e871168 commit 8e5254d

4 files changed

Lines changed: 75 additions & 10 deletions

File tree

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ export default function Page({url, navigate}) {
6262
<ViewTransition className={transitions['slide-on-nav']}>
6363
<h1>{!show ? 'A' : 'B'}</h1>
6464
</ViewTransition>
65+
<ViewTransition
66+
className={{
67+
'navigation-back': transitions['slide-right'],
68+
'navigation-forward': transitions['slide-left'],
69+
}}>
70+
<h1>{!show ? 'A' : 'B'}</h1>
71+
</ViewTransition>
6572
{show ? (
6673
<div>
6774
{a}

fixtures/view-transition/src/components/Transitions.module.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@
4242
}
4343
}
4444

45+
::view-transition-new(.slide-right) {
46+
animation: enter-slide-right ease-in 0.25s;
47+
}
48+
::view-transition-old(.slide-right) {
49+
animation: exit-slide-right ease-in 0.25s;
50+
}
51+
::view-transition-new(.slide-left) {
52+
animation: enter-slide-left ease-in 0.25s;
53+
}
54+
::view-transition-old(.slide-left) {
55+
animation: exit-slide-left ease-in 0.25s;
56+
}
57+
4558
::view-transition-new(.enter-slide-right):only-child {
4659
animation: enter-slide-right ease-in 0.25s;
4760
}

packages/react-reconciler/src/ReactFiberViewTransitionComponent.js

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,30 @@ import type {ReactNodeList} from 'shared/ReactTypes';
1111
import type {FiberRoot} from './ReactInternalTypes';
1212
import type {ViewTransitionInstance} from './ReactFiberConfig';
1313

14-
import {getWorkInProgressRoot} from './ReactFiberWorkLoop';
14+
import {
15+
getWorkInProgressRoot,
16+
getPendingTransitionTypes,
17+
} from './ReactFiberWorkLoop';
1518

1619
import {getIsHydrating} from './ReactFiberHydrationContext';
1720

1821
import {getTreeId} from './ReactFiberTreeContext';
1922

23+
export type ViewTransitionClassPerType = {
24+
[transitionType: 'default' | string]: 'none' | string,
25+
};
26+
27+
export type ViewTransitionClass = 'none' | string | ViewTransitionClassPerType;
28+
2029
export type ViewTransitionProps = {
2130
name?: string,
2231
children?: ReactNodeList,
23-
className?: 'none' | string,
24-
enter?: 'none' | string,
25-
exit?: 'none' | string,
26-
layout?: 'none' | string,
27-
share?: 'none' | string,
28-
update?: 'none' | string,
32+
className?: ViewTransitionClass,
33+
enter?: ViewTransitionClass,
34+
exit?: ViewTransitionClass,
35+
layout?: ViewTransitionClass,
36+
share?: ViewTransitionClass,
37+
update?: ViewTransitionClass,
2938
onEnter?: (instance: ViewTransitionInstance, types: Array<string>) => void,
3039
onExit?: (instance: ViewTransitionInstance, types: Array<string>) => void,
3140
onLayout?: (instance: ViewTransitionInstance, types: Array<string>) => void,
@@ -82,17 +91,49 @@ export function getViewTransitionName(
8291
return (instance.autoName: any);
8392
}
8493

94+
function getClassNameByType(classByType: ?ViewTransitionClass): ?string {
95+
if (classByType == null || typeof classByType === 'string') {
96+
return classByType;
97+
}
98+
let className: ?string = null;
99+
const activeTypes = getPendingTransitionTypes();
100+
if (activeTypes !== null) {
101+
for (let i = 0; i < activeTypes.length; i++) {
102+
const match = classByType[activeTypes[i]];
103+
if (match != null) {
104+
if (match === 'none') {
105+
// If anything matches "none" that takes precedence over any other
106+
// type that also matches.
107+
return 'none';
108+
}
109+
if (className == null) {
110+
className = match;
111+
} else {
112+
className += ' ' + match;
113+
}
114+
}
115+
}
116+
}
117+
if (className == null) {
118+
// We had no other matches. Match the default for this configuration.
119+
return classByType.default;
120+
}
121+
return className;
122+
}
123+
85124
export function getViewTransitionClassName(
86-
className: ?string,
87-
eventClassName: ?string,
125+
defaultClass: ?ViewTransitionClass,
126+
eventClass: ?ViewTransitionClass,
88127
): ?string {
128+
const className: ?string = getClassNameByType(defaultClass);
129+
const eventClassName: ?string = getClassNameByType(eventClass);
89130
if (eventClassName == null) {
90131
return className;
91132
}
92133
if (eventClassName === 'none') {
93134
return eventClassName;
94135
}
95-
if (className != null) {
136+
if (className != null && className !== 'none') {
96137
return className + ' ' + eventClassName;
97138
}
98139
return eventClassName;

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,10 @@ export function getPendingPassiveEffectsLanes(): Lanes {
698698
return pendingEffectsLanes;
699699
}
700700

701+
export function getPendingTransitionTypes(): null | TransitionTypes {
702+
return pendingTransitionTypes;
703+
}
704+
701705
export function isWorkLoopSuspendedOnData(): boolean {
702706
return (
703707
workInProgressSuspendedReason === SuspendedOnData ||

0 commit comments

Comments
 (0)