Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fa509c1
Add enableViewTransitionForPersistenceMode feature flag
zeyap Mar 11, 2026
f291958
Simplify persistence mode view transition logic
zeyap Mar 18, 2026
bad3c40
Early return in restoreViewTransitionOnHostInstances for non-mutation…
zeyap Mar 18, 2026
2e0f097
Refactor applyViewTransitionToHostInstancesRecursive to early return …
zeyap Mar 18, 2026
b5868c7
Refactor measureViewTransitionHostInstancesRecursive to early return …
zeyap Mar 19, 2026
3364161
Fix formatting and restructure persistence mode early returns
zeyap Mar 19, 2026
2c74b71
Add TODO and comments for persistence mode measure logic
zeyap Mar 19, 2026
a0ed77d
Make enableViewTransitionForPersistenceMode a dynamic feature flag
zeyap Mar 19, 2026
33b503d
create supportsViewTransition and ReactFiberConfigWithNoViewTransitio…
zeyap Mar 5, 2026
1f1ecf5
create supportsViewTransition and ReactFiberConfigWithNoViewTransitio…
zeyap Mar 5, 2026
5d9cf14
enableViewTransition for RN
zeyap Feb 5, 2026
48dede4
invoke FabricUIManager methods
zeyap Feb 6, 2026
a7a00e3
Rename fabricStartViewTransition to fabricViewTransitionStarted
zeyap Feb 6, 2026
55669e6
restore/cancelViewTransitionName; fallback behavior if fabric doesnt …
zeyap Feb 11, 2026
ef247be
fix flow
zeyap Feb 11, 2026
6fb21be
prettier
zeyap Feb 11, 2026
85fdaa0
make startViewTransition async and return ready & finished promises
zeyap Feb 13, 2026
c9ba98d
update startViewTransition to use ready/finished promise returned fro…
zeyap Feb 25, 2026
b3428f2
move vt specific config functions to ReactFiberConfigFabricWithViewTr…
zeyap Mar 5, 2026
cdaf33e
implement function createViewTransitionInstance
zeyap Mar 5, 2026
7a1f5b6
cleanup
zeyap Mar 6, 2026
76241be
Remove supportsViewTransition config, let each renderer handle view t…
zeyap Mar 19, 2026
e453b72
Fix Fabric view transition types and restore shim() for disabled flag
zeyap Mar 19, 2026
0c0ccdc
Simplify Fabric view transition stubs and enable enableViewTransition…
zeyap Mar 19, 2026
f1a7a1e
Remove unused Fabric native view transition Flow declarations
zeyap Mar 19, 2026
d11a095
Remove unused imports and fix formatting
zeyap Mar 19, 2026
64d367f
Silence cancelRootViewTransitionName and restoreRootViewTransitionNam…
zeyap Mar 19, 2026
2973299
Fix startGestureTransition to return resolved promises instead of pen…
zeyap Mar 19, 2026
50017ba
Add ReactFiberConfigWithNoViewTransition shim for noop renderer
zeyap Mar 19, 2026
3a57887
Retry CI
zeyap Mar 19, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ export * from 'react-reconciler/src/ReactFiberConfigWithNoScopes';
export * from 'react-reconciler/src/ReactFiberConfigWithNoTestSelectors';
export * from 'react-reconciler/src/ReactFiberConfigWithNoResources';
export * from 'react-reconciler/src/ReactFiberConfigWithNoSingletons';
export * from './ReactFiberConfigFabricWithViewTransition';

export function appendInitialChild(
parentInstance: Instance,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type {TransitionTypes} from 'react/src/ReactTransitionType';
import type {
Instance,
Props,
Container,
SuspendedState,
GestureTimeline,
} from './ReactFiberConfigFabric';

const {
applyViewTransitionName: fabricApplyViewTransitionName,
startViewTransition: fabricStartViewTransition,
} = nativeFabricUIManager;

export type InstanceMeasurement = {
rect: {x: number, y: number, width: number, height: number},
abs: boolean,
clip: boolean,
view: boolean,
};

export type RunningViewTransition = {
finished: Promise<void>,
ready: Promise<void>,
...
};

interface ViewTransitionPseudoElementType extends mixin$Animatable {
_pseudo: string;
_name: string;
}

function ViewTransitionPseudoElement(
this: ViewTransitionPseudoElementType,
pseudo: string,
name: string,
) {
// TODO: Get the owner document from the root container.
this._pseudo = pseudo;
this._name = name;
}

export type ViewTransitionInstance = null | {
name: string,
old: mixin$Animatable,
new: mixin$Animatable,
...
};

export function restoreViewTransitionName(
instance: Instance,
props: Props,
): void {
if (__DEV__) {
console.warn('restoreViewTransitionName is not implemented');
}
}

// Cancel the old and new snapshots of viewTransitionName
export function cancelViewTransitionName(
instance: Instance,
oldName: string,
props: Props,
): void {
if (__DEV__) {
console.warn('cancelViewTransitionName is not implemented');
}
}

export function cancelRootViewTransitionName(rootContainer: Container): void {
// No-op
}

export function restoreRootViewTransitionName(rootContainer: Container): void {
// No-op
}

export function cloneRootViewTransitionContainer(
rootContainer: Container,
): Instance {
if (__DEV__) {
console.warn('cloneRootViewTransitionContainer is not implemented');
}
// $FlowFixMe[incompatible-return] Return empty stub
return null;
}

export function removeRootViewTransitionClone(
rootContainer: Container,
clone: Instance,
): void {
if (__DEV__) {
console.warn('removeRootViewTransitionClone is not implemented');
}
}

export function measureInstance(instance: Instance): InstanceMeasurement {
if (__DEV__) {
console.warn('measureInstance is not implemented');
}
return {
rect: {
x: 0,
y: 0,
width: 0,
height: 0,
},
abs: false,
clip: false,
// TODO: properly calculate whether instance is in viewport
view: true,
};
}

export function measureClonedInstance(instance: Instance): InstanceMeasurement {
if (__DEV__) {
console.warn('measureClonedInstance is not implemented');
}
return {
rect: {x: 0, y: 0, width: 0, height: 0},
abs: false,
clip: false,
view: true,
};
}

export function wasInstanceInViewport(
measurement: InstanceMeasurement,
): boolean {
return measurement.view;
}

export function hasInstanceChanged(
oldMeasurement: InstanceMeasurement,
newMeasurement: InstanceMeasurement,
): boolean {
if (__DEV__) {
console.warn('hasInstanceChanged is not implemented');
}
return false;
}

export function hasInstanceAffectedParent(
oldMeasurement: InstanceMeasurement,
newMeasurement: InstanceMeasurement,
): boolean {
if (__DEV__) {
console.warn('hasInstanceAffectedParent is not implemented');
}
return false;
}

export function startGestureTransition(
suspendedState: null | SuspendedState,
rootContainer: Container,
timeline: GestureTimeline,
rangeStart: number,
rangeEnd: number,
transitionTypes: null | TransitionTypes,
mutationCallback: () => void,
animateCallback: () => void,
errorCallback: (error: mixed) => void,
finishedAnimation: () => void,
): RunningViewTransition {
if (__DEV__) {
console.warn('startGestureTransition is not implemented');
}
return {
finished: Promise.resolve(),
ready: Promise.resolve(),
};
}

export function stopViewTransition(transition: RunningViewTransition): void {
if (__DEV__) {
console.warn('stopViewTransition is not implemented');
}
}

export function addViewTransitionFinishedListener(
transition: RunningViewTransition,
callback: () => void,
): void {
transition.finished.finally(callback);
}

export function createViewTransitionInstance(
name: string,
): ViewTransitionInstance {
return {
name,
old: new (ViewTransitionPseudoElement: any)('old', name),
new: new (ViewTransitionPseudoElement: any)('new', name),
};
}

export function applyViewTransitionName(
instance: Instance,
name: string,
className: ?string,
): void {
// add view-transition-name to things that might animate for browser
fabricApplyViewTransitionName(instance.node, name, className);
}

export function startViewTransition(
suspendedState: null | SuspendedState,
rootContainer: Container,
transitionTypes: null | TransitionTypes,
mutationCallback: () => void,
layoutCallback: () => void,
afterMutationCallback: () => void,
spawnedWorkCallback: () => void,
passiveCallback: () => mixed,
errorCallback: (error: mixed) => void,
blockedCallback: (name: string) => void,
finishedAnimation: () => void,
): null | RunningViewTransition {
const transition = fabricStartViewTransition(
// mutation
() => {
mutationCallback(); // completeRoot should run here
layoutCallback();
afterMutationCallback();
},
);

if (transition == null) {
if (__DEV__) {
console.warn(
"startViewTransition didn't kick off transition in Fabric, the ViewTransition ReactNativeFeatureFlag might not be enabled.",
);
}
// Flush remaining work synchronously.
mutationCallback();
layoutCallback();
// Skip afterMutationCallback(). We don't need it since we're not animating.
spawnedWorkCallback();
// Skip passiveCallback(). Spawned work will schedule a task.
return null;
}

transition.ready.then(() => {
spawnedWorkCallback();
});

transition.finished.finally(() => {
passiveCallback();
});

return transition;
}
4 changes: 3 additions & 1 deletion packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type {EventPriority} from 'react-reconciler/src/ReactEventPriorities';
import type {TransitionTypes} from 'react/src/ReactTransitionType';
import typeof * as HostConfig from 'react-reconciler/src/ReactFiberConfig';
import typeof * as ReactFiberConfigWithNoMutation from 'react-reconciler/src/ReactFiberConfigWithNoMutation';
import typeof * as ReactFiberConfigWithNoViewTransition from 'react-reconciler/src/ReactFiberConfigWithNoViewTransition';
import typeof * as ReactFiberConfigWithNoPersistence from 'react-reconciler/src/ReactFiberConfigWithNoPersistence';

import typeof * as ReconcilerAPI from 'react-reconciler/src/ReactFiberReconciler';
Expand Down Expand Up @@ -709,7 +710,8 @@ function createReactNoop(

const mutationHostConfig: Pick<
HostConfig,
$Keys<ReactFiberConfigWithNoMutation>,
| $Keys<ReactFiberConfigWithNoMutation>
| $Keys<ReactFiberConfigWithNoViewTransition>,
> = {
supportsMutation: true,

Expand Down
Loading
Loading