Skip to content

Allow waiting for user land Animated animations before firing transition complete callback (#56459)#56459

Closed
zeyap wants to merge 8 commits intofacebook:mainfrom
zeyap:export-D99366980
Closed

Allow waiting for user land Animated animations before firing transition complete callback (#56459)#56459
zeyap wants to merge 8 commits intofacebook:mainfrom
zeyap:export-D99366980

Conversation

@zeyap
Copy link
Copy Markdown
Contributor

@zeyap zeyap commented Apr 15, 2026

Summary:

Changelog:

[Internal] [Added] - Allow waiting for user land Animated animations before firing transition complete callback

Instead of calling onCompleteCallback synchronously at the end of startViewTransition, defer it until all animations have finished. Since transition animation can be kicked off in user land from view transition event handlers, we need extra APIs to signal to native side when animation starts and finishes. This ensures the transition lifecycle properly waits for native animated transitions to complete.

  • Add waitForTransitionAnimation / transitionAnimationFinished to the delegate interface and expose via NativeViewTransition TurboModule
  • JS calls waitForTransitionAnimation(animationId) before starting each animation and transitionAnimationFinished(animationId) in the completion callback
  • ViewTransitionModule tracks pending animation IDs in a std::set and fires onCompleteCallback_ only when all animations are done
    • only track and wait for animations started during transition-ready callback
  • if no animation requests to be waited for, resolve complete promise immediately when transition-ready callback finishes

Reviewed By: sammy-SC

Differential Revision: D99366980

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Apr 15, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented Apr 15, 2026

@zeyap has exported this pull request. If you are a Meta employee, you can view the originating Diff in D99366980.

zeyap added a commit to zeyap/react-native that referenced this pull request Apr 15, 2026
…ion complete callback (facebook#56459)

Summary:
Pull Request resolved: facebook#56459

## Changelog:

[Internal] [Added] - Allow waiting for user land Animated animations before firing transition complete callback

Instead of calling `onCompleteCallback` synchronously at the end of `startViewTransition`, defer it until all animations have finished. Since transition animation can be kicked off in user land from view transition event handlers, we need extra APIs to signal to native side when animation starts and finishes. This ensures the transition lifecycle properly waits for native animated transitions to complete.

- Add `waitForTransitionAnimation` / `transitionAnimationFinished` to the delegate interface and expose via `NativeViewTransition` TurboModule
- JS calls `waitForTransitionAnimation(animationId)` before starting each animation and `transitionAnimationFinished(animationId)` in the completion callback
- `ViewTransitionModule` tracks pending animation IDs in a `std::set` and fires `onCompleteCallback_` only when all animations are done
   - only track and wait for animations started during transition-ready callback
- if no animation requests to be waited for, resolve complete promise immediately when transition-ready callback finishes

Reviewed By: sammy-SC

Differential Revision: D99366980
@meta-codesync meta-codesync Bot changed the title Allow waiting for user land Animated animations before firing transition complete callback Allow waiting for user land Animated animations before firing transition complete callback (#56459) Apr 15, 2026
@zeyap zeyap force-pushed the export-D99366980 branch from 3c17831 to c96c56a Compare April 15, 2026 18:17
zeyap added a commit to zeyap/react-native that referenced this pull request Apr 15, 2026
…ion complete callback (facebook#56459)

Summary:
Pull Request resolved: facebook#56459

## Changelog:

[Internal] [Added] - Allow waiting for user land Animated animations before firing transition complete callback

Instead of calling `onCompleteCallback` synchronously at the end of `startViewTransition`, defer it until all animations have finished. Since transition animation can be kicked off in user land from view transition event handlers, we need extra APIs to signal to native side when animation starts and finishes. This ensures the transition lifecycle properly waits for native animated transitions to complete.

- Add `waitForTransitionAnimation` / `transitionAnimationFinished` to the delegate interface and expose via `NativeViewTransition` TurboModule
- JS calls `waitForTransitionAnimation(animationId)` before starting each animation and `transitionAnimationFinished(animationId)` in the completion callback
- `ViewTransitionModule` tracks pending animation IDs in a `std::set` and fires `onCompleteCallback_` only when all animations are done
   - only track and wait for animations started during transition-ready callback
- if no animation requests to be waited for, resolve complete promise immediately when transition-ready callback finishes

Reviewed By: sammy-SC

Differential Revision: D99366980
@zeyap zeyap force-pushed the export-D99366980 branch from c96c56a to 7693e9c Compare April 15, 2026 18:30
Zeya Peng added 7 commits April 15, 2026 11:50
Summary:
Implement `createViewTransitionInstance`, which is invoked by the React reconciler to create pseudo-element shadow nodes that visually represent the old state of elements participating in a view transition.

Key changes:
- Add `createViewTransitionInstance` JSI binding in `UIManagerBinding`, accepting a transition name and pseudo-element tag
- Add virtual `createViewTransitionInstance` method to `UIManagerViewTransitionDelegate`
- Implement the method in `ViewTransitionModule`: creates an absolutely-positioned, non-interactive `View` shadow node matching the old element's layout metrics (position, size)
- Manage two pseudo-element node maps: `oldPseudoElementNodes_` for the current transition and `oldPseudoElementNodesForNextTransition_` for entering nodes that may exit in a future transition
- Update `getOldViewTransitionInstance` to return the pseudo-element's tag (instead of the original element's tag) when a pseudo-element exists
- Add `applySnapshotsOnPseudoElementShadowNodes` stub for future platform-level bitmap snapshot integration

`createViewTransitionInstance` is typically called after `applyViewTransitionName` in the React reconciler. See the diagram below for the full flow.

{F1987481080}

Differential Revision: D98981886
Summary:
Append view transition pseudo-element shadow nodes to the root's children at commit time (`shadowTreeWillCommit`), so they are committed into the shadow tree and rendered by the platform.

Key changes:
- Add `getPseudoElementNodes(surfaceId)` virtual method to `UIManagerViewTransitionDelegate`, returning pseudo-element shadow nodes filtered by surface ID
- Implement the method in `ViewTransitionModule`, iterating over `oldPseudoElementNodes_` and collecting nodes matching the given surface
- In `shadowTreeWillCommit`, when view transitions are enabled, query the delegate for pseudo-element nodes and insert them at the end of `rootChildren` before committing

This ensures pseudo-element nodes (created by `createViewTransitionInstance`) are included in the committed shadow tree and ultimately mounted as platform views that display old-element snapshots during transitions.

Differential Revision: D98982122
Summary:
Add `findPseudoElementShadowNodeByTag` to look up pseudo-element shadow nodes by tag from JS, and update the animation helper to connect animated nodes to pseudo-element shadow nodes for old-element animations.

Key changes:
- Add `findPseudoElementShadowNodeByTag(tag)` virtual method to `UIManagerViewTransitionDelegate` and implement in `ViewTransitionModule` (linear scan over `oldPseudoElementNodes_`)
- Expose the method via `NativeViewTransition` TurboModule so JS can resolve a pseudo-element's shadow node by its native tag
- Add `findPseudoElementShadowNodeByTag` to `NativeViewTransition.js` spec
- Update `ViewTransitionAnimationHelper.js`:
  - `animateInternal` accepts a new `pseudo` parameter (`'old'` | `'new'`)
  - When `pseudo === 'old'`, use `findPseudoElementShadowNodeByTag` instead of `findShadowNodeByTag_DEPRECATED` to connect animated nodes to the correct shadow node family
  - Pass `'new'` for enter animations and propagate `_pseudo` from pseudo-element objects for exit animations

Differential Revision: D98982251
Summary:
Wire view transition bitmap snapshot capture and display through the C++
delegate chain so platforms can implement snapshotting old-element views.

**ViewTransitionModule.cpp**: Call `uiManagerDidCaptureViewSnapshot(tag,
surfaceId)` in `applyViewTransitionName` to capture a bitmap of the old view
while it is still mounted, and `uiManagerDidSetViewSnapshot(sourceTag,
targetTag, surfaceId)` in `applySnapshotsOnPseudoElementShadowNodes` to map
captured bitmaps onto pseudo-element views.

**UIManagerDelegate / SchedulerDelegate**: Add pure virtual
`captureViewSnapshot` and `setViewSnapshot` methods.

**Scheduler**: Forward `UIManagerDelegate` calls to `SchedulerDelegate`.

**Platform stubs**: Empty implementations for iOS (`RCTScheduler.mm`),
CxxPlatform (`SchedulerDelegateImpl`), and Android JNI
(`FabricUIManagerBinding`) — Android implementation follows in D99173446.

Differential Revision: D98354659
Summary:
Implement the Android side of view transition bitmap snapshots.

**`ViewTransitionSnapshotManager`** (new Kotlin class):
Manages the full snapshot lifecycle as a `UIManagerListener`. Captures bitmaps
on the UI thread, maps them from source to target pseudo-element tags,
re-applies after mount cycles (since views may be recreated), and self-cleans
when views are deleted.

**JNI bridge:**
`FabricUIManagerBinding` → `FabricMountingManager` → `FabricUIManager` JNI
delegates to the snapshot manager.

**`SurfaceMountingManager.applyViewSnapshot`:** sets bitmap as view background
using the KTX `Bitmap.toDrawable` extension.

Differential Revision: D99173446
Summary:
When a new view transition starts while another is still active, queue it instead of running immediately. The queued transition runs after the current one finishes via `startViewTransitionEnd`.

- Add `suspendOnActiveViewTransition()` to `UIManagerViewTransitionDelegate`, exposed as a method on `nativeFabricUIManager` so the reconciler can signal suspension
- `ViewTransitionModule` queues pending transitions in a `std::queue<PendingTransition>` when `suspendNextTransition_` is set
- `startViewTransitionEnd` drains the queue sequentially, each transition triggering the next on completion

Differential Revision: D99366975
Summary:
Add `startViewTransitionReadyFinished()` to the view transition delegate so the reconciler can notify the native side when the ready callback's async work (e.g. spawned work from the `ready` promise `.then`) has completed. This was previously not capturable from the C++ side since `onReadyCallback` resolves the JS promise synchronously but the reconciler's follow-up work runs as a microtask.

- Add `startViewTransitionReadyFinished` to `UIManagerViewTransitionDelegate` and `ViewTransitionModule`
- Expose as a method on `nativeFabricUIManager` via `UIManagerBinding`
- Track `transitionReadyFinished_` state, reset to `false` before `onReadyCallback` and set to `true` when the reconciler calls back

Differential Revision: D99443648
Copy link
Copy Markdown

@rachel11026725 rachel11026725 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay cool

zeyap added a commit to zeyap/react-native that referenced this pull request Apr 15, 2026
…ion complete callback (facebook#56459)

Summary:
Pull Request resolved: facebook#56459

## Changelog:

[Internal] [Added] - Allow waiting for user land Animated animations before firing transition complete callback

Instead of calling `onCompleteCallback` synchronously at the end of `startViewTransition`, defer it until all animations have finished. Since transition animation can be kicked off in user land from view transition event handlers, we need extra APIs to signal to native side when animation starts and finishes. This ensures the transition lifecycle properly waits for native animated transitions to complete.

- Add `waitForTransitionAnimation` / `transitionAnimationFinished` to the delegate interface and expose via `NativeViewTransition` TurboModule
- JS calls `waitForTransitionAnimation(animationId)` before starting each animation and `transitionAnimationFinished(animationId)` in the completion callback
- `ViewTransitionModule` tracks pending animation IDs in a `std::set` and fires `onCompleteCallback_` only when all animations are done
   - only track and wait for animations started during transition-ready callback
- if no animation requests to be waited for, resolve complete promise immediately when transition-ready callback finishes

Reviewed By: sammy-SC

Differential Revision: D99366980
@zeyap zeyap force-pushed the export-D99366980 branch from 7693e9c to 9c46c0b Compare April 15, 2026 19:06
…ion complete callback (facebook#56459)

Summary:
Pull Request resolved: facebook#56459

## Changelog:

[Internal] [Added] - Allow waiting for user land Animated animations before firing transition complete callback

Instead of calling `onCompleteCallback` synchronously at the end of `startViewTransition`, defer it until all animations have finished. Since transition animation can be kicked off in user land from view transition event handlers, we need extra APIs to signal to native side when animation starts and finishes. This ensures the transition lifecycle properly waits for native animated transitions to complete.

- Add `waitForTransitionAnimation` / `transitionAnimationFinished` to the delegate interface and expose via `NativeViewTransition` TurboModule
- JS calls `waitForTransitionAnimation(animationId)` before starting each animation and `transitionAnimationFinished(animationId)` in the completion callback
- `ViewTransitionModule` tracks pending animation IDs in a `std::set` and fires `onCompleteCallback_` only when all animations are done
   - only track and wait for animations started during transition-ready callback
- if no animation requests to be waited for, resolve complete promise immediately when transition-ready callback finishes

Reviewed By: sammy-SC

Differential Revision: D99366980
@zeyap zeyap force-pushed the export-D99366980 branch from 9c46c0b to 9fc2e8e Compare April 15, 2026 20:33
@meta-codesync meta-codesync Bot closed this in a4f78b3 Apr 16, 2026
@facebook-github-tools facebook-github-tools Bot added the Merged This PR has been merged. label Apr 16, 2026
@meta-codesync
Copy link
Copy Markdown

meta-codesync Bot commented Apr 16, 2026

This pull request has been merged in a4f78b3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants