Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions fixtures/view-transition/src/components/Page.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
.roboto-font {
font-family: "Roboto", serif;
font-optical-sizing: auto;
font-weight: 100;
font-style: normal;
font-variation-settings:
"wdth" 100;
}

.swipe-recognizer {
width: 300px;
background: #eee;
Expand Down
21 changes: 21 additions & 0 deletions fixtures/view-transition/src/components/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
Activity,
useLayoutEffect,
useEffect,
useInsertionEffect,
useState,
useId,
useOptimistic,
Expand Down Expand Up @@ -41,6 +42,26 @@ const b = (
);

function Component() {
// Test inserting fonts with style tags using useInsertionEffect. This is not recommended but
// used to test that gestures etc works with useInsertionEffect so that stylesheet based
// libraries can be properly supported.
useInsertionEffect(() => {
const style = document.createElement('style');
style.textContent = `
.roboto-font {
font-family: "Roboto", serif;
font-optical-sizing: auto;
font-weight: 100;
font-style: normal;
font-variation-settings:
"wdth" 100;
}
`;
document.head.appendChild(style);
return () => {
document.head.removeChild(style);
};
}, []);
return (
<ViewTransition
default={
Expand Down
107 changes: 91 additions & 16 deletions packages/react-reconciler/src/ReactFiberApplyGesture.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
} from './ReactFiberMutationTracking';
import {
MutationMask,
Placement,
Update,
ContentReset,
NoFlags,
Expand All @@ -52,6 +53,14 @@ import {
AffectedParentLayout,
} from './ReactFiberFlags';
import {
HasEffect as HookHasEffect,
Insertion as HookInsertion,
} from './ReactHookEffectTags';
import {
FunctionComponent,
ForwardRef,
MemoComponent,
SimpleMemoComponent,
HostComponent,
HostHoistable,
HostSingleton,
Expand All @@ -72,6 +81,10 @@ import {
pushViewTransitionCancelableScope,
popViewTransitionCancelableScope,
} from './ReactFiberCommitViewTransitions';
import {
commitHookEffectListMount,
commitHookEffectListUnmount,
} from './ReactFiberCommitEffects';
import {
getViewTransitionName,
getViewTransitionClassName,
Expand Down Expand Up @@ -371,9 +384,10 @@ function recursivelyInsertNew(
if (
visitPhase === INSERT_APPEARING_PAIR &&
parentViewTransition === null &&
(parentFiber.subtreeFlags & ViewTransitionNamedStatic) === NoFlags
(parentFiber.subtreeFlags & (ViewTransitionNamedStatic | Placement)) ===
NoFlags
) {
// We're just searching for pairs but we have reached the end.
// We're just searching for pairs or insertion effects but we have reached the end.
return;
}
let child = parentFiber.child;
Expand All @@ -395,6 +409,28 @@ function recursivelyInsertNewFiber(
visitPhase: VisitPhase,
): void {
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case MemoComponent:
case SimpleMemoComponent: {
recursivelyInsertNew(
finishedWork,
hostParentClone,
parentViewTransition,
visitPhase,
);
if (finishedWork.flags & Update) {
// Insertion Effects are mounted temporarily during the rendering of the snapshot.
// This does not affect cloned Offscreen content since those would've been mounted
// while inside the offscreen tree already.
// Note that because we are mounting a clone of the DOM tree and the previous DOM
// tree remains mounted during the snapshot, we can't unmount any previous insertion
// effects. This can lead to conflicts but that is similar to what can happen with
// conflicts for two mounted Activity boundaries.
commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);
}
break;
}
case HostHoistable: {
if (supportsResources) {
// TODO: Hoistables should get optimistically inserted and then removed.
Expand Down Expand Up @@ -1032,6 +1068,40 @@ function measureExitViewTransitions(placement: Fiber): void {
}
}

function recursivelyRestoreNew(
finishedWork: Fiber,
nearestMountedAncestor: Fiber,
): void {
// There has to be move a Placement AND an Update flag somewhere below for this
// pass to be relevant since we only apply insertion effects for new components here.
if (((Placement | Update) & finishedWork.subtreeFlags) !== NoFlags) {
let child = finishedWork.child;
while (child !== null) {
recursivelyRestoreNew(child, nearestMountedAncestor);
child = child.sibling;
}
}
switch (finishedWork.tag) {
case FunctionComponent:
case ForwardRef:
case MemoComponent:
case SimpleMemoComponent: {
const current = finishedWork.alternate;
if (current === null && finishedWork.flags & Update) {
// Insertion Effects are mounted temporarily during the rendering of the snapshot.
// We have now already takes a snapshot of the inserted state so we can now unmount
// them to get back into the original state before starting the animation.
commitHookEffectListUnmount(
HookInsertion | HookHasEffect,
finishedWork,
nearestMountedAncestor,
);
}
break;
}
}
}

function recursivelyApplyViewTransitions(parentFiber: Fiber) {
const deletions = parentFiber.deletions;
if (deletions !== null) {
Expand All @@ -1048,7 +1118,13 @@ function recursivelyApplyViewTransitions(parentFiber: Fiber) {
// If we have mutations or if this is a newly inserted tree, clone as we go.
let child = parentFiber.child;
while (child !== null) {
applyViewTransitionsOnFiber(child);
const current = child.alternate;
if (current === null) {
measureExitViewTransitions(child);
recursivelyRestoreNew(child, parentFiber);
} else {
applyViewTransitionsOnFiber(child, current);
}
child = child.sibling;
}
} else {
Expand All @@ -1059,14 +1135,7 @@ function recursivelyApplyViewTransitions(parentFiber: Fiber) {
}
}

function applyViewTransitionsOnFiber(finishedWork: Fiber) {
const current = finishedWork.alternate;
if (current === null) {
measureExitViewTransitions(finishedWork);
return;
}

const flags = finishedWork.flags;
function applyViewTransitionsOnFiber(finishedWork: Fiber, current: Fiber) {
// The effect flag should be checked *after* we refine the type of fiber,
// because the fiber tag is more specific. An exception is any flag related
// to reconciliation, because those can be set on all fiber types.
Expand All @@ -1076,12 +1145,18 @@ function applyViewTransitionsOnFiber(finishedWork: Fiber) {
break;
}
case OffscreenComponent: {
if (flags & Visibility) {
const newState: OffscreenState | null = finishedWork.memoizedState;
const isHidden = newState !== null;
if (!isHidden) {
const newState: OffscreenState | null = finishedWork.memoizedState;
const isHidden = newState !== null;
const wasHidden = current.memoizedState !== null;
if (!isHidden) {
if (wasHidden) {
measureExitViewTransitions(finishedWork);
} else if (current !== null && current.memoizedState === null) {
recursivelyRestoreNew(finishedWork, finishedWork);
} else {
recursivelyApplyViewTransitions(finishedWork);
}
} else {
if (!wasHidden) {
// Was previously mounted as visible but is now hidden.
commitEnterViewTransitions(current, true);
}
Expand Down
Loading