Skip to content

Commit d8820a4

Browse files
zeyapmeta-codesync[bot]
authored andcommitted
Add unstable_getViewTransitionInstance to UIManagerBinding (#55940)
Summary: Pull Request resolved: #55940 Adds `unstable_getViewTransitionInstance` API to UIManagerBinding and FabricUIManager, allowing JavaScript to retrieve position and dimension information for view transition pseudo-elements. This enables us to obtain pseudo element created on the runtime and manipulate them. React allows imperative animation commands like below: ``` <ViewTransition onEnter={(instance)=>{ instance.new.animate(...); }} > // ... </ViewTransition> ``` on RN we could support something similar, e.g. letting user animate the new instance with Animated at VT event handlers, this could potentially guarantee smooth animation, since when onEnter is invoked, new shadow tree is committed but native view should not be mounted yet. ## Changelog: [General] [Added] - Add unstable_getViewTransitionInstance to UIManagerBinding Reviewed By: sammy-SC Differential Revision: D94956110 fbshipit-source-id: 1d243b308033ce927b282e91a271d995fac226cc
1 parent d83bf73 commit d8820a4

5 files changed

Lines changed: 100 additions & 0 deletions

File tree

packages/react-native/Libraries/ReactNative/FabricUIManager.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ export interface Spec {
9797
+unstable_ContinuousEventPriority: number;
9898
+unstable_IdleEventPriority: number;
9999
+unstable_getCurrentEventPriority: () => number;
100+
+unstable_getViewTransitionInstance: (
101+
name: string,
102+
pseudo: string,
103+
) => ?{
104+
x: number,
105+
y: number,
106+
width: number,
107+
height: number,
108+
nativeTag: number,
109+
};
100110
}
101111

102112
let nativeFabricUIManagerProxy: ?Spec;
@@ -129,6 +139,7 @@ const CACHED_PROPERTIES = [
129139
'unstable_ContinuousEventPriority',
130140
'unstable_IdleEventPriority',
131141
'unstable_getCurrentEventPriority',
142+
'unstable_getViewTransitionInstance',
132143
];
133144

134145
// This is exposed as a getter because apps using the legacy renderer AND

packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,43 @@ jsi::Value UIManagerBinding::get(
11521152
});
11531153
}
11541154

1155+
if (methodName == "unstable_getViewTransitionInstance") {
1156+
auto paramCount = 2;
1157+
return jsi::Function::createFromHostFunction(
1158+
runtime,
1159+
name,
1160+
paramCount,
1161+
[uiManager, methodName, paramCount](
1162+
jsi::Runtime& runtime,
1163+
const jsi::Value& /*thisValue*/,
1164+
const jsi::Value* arguments,
1165+
size_t count) -> jsi::Value {
1166+
validateArgumentCount(runtime, methodName, paramCount, count);
1167+
1168+
auto nameStr = arguments[0].asString(runtime).utf8(runtime);
1169+
auto pseudoStr = arguments[1].asString(runtime).utf8(runtime);
1170+
1171+
auto* viewTransitionDelegate = uiManager->getViewTransitionDelegate();
1172+
if (viewTransitionDelegate == nullptr) {
1173+
return jsi::Value::undefined();
1174+
}
1175+
1176+
auto instance = viewTransitionDelegate->getViewTransitionInstance(
1177+
nameStr, pseudoStr);
1178+
if (!instance) {
1179+
return jsi::Value::undefined();
1180+
}
1181+
auto result = jsi::Object(runtime);
1182+
result.setProperty(runtime, "x", instance->x);
1183+
result.setProperty(runtime, "y", instance->y);
1184+
result.setProperty(runtime, "width", instance->width);
1185+
result.setProperty(runtime, "height", instance->height);
1186+
result.setProperty(
1187+
runtime, "nativeTag", static_cast<double>(instance->nativeTag));
1188+
return result;
1189+
});
1190+
}
1191+
11551192
return jsi::Value::undefined();
11561193
}
11571194

packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerViewTransitionDelegate.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
#pragma once
99

1010
#include <react/renderer/core/ShadowNode.h>
11+
#include <react/renderer/graphics/Float.h>
1112
#include <functional>
13+
#include <optional>
1214

1315
namespace facebook::react {
1416

@@ -35,6 +37,21 @@ class UIManagerViewTransitionDelegate {
3537
}
3638

3739
virtual void startViewTransitionEnd() {}
40+
41+
struct ViewTransitionInstance {
42+
Float x{0};
43+
Float y{0};
44+
Float width{0};
45+
Float height{0};
46+
Tag nativeTag{-1};
47+
};
48+
49+
virtual std::optional<ViewTransitionInstance> getViewTransitionInstance(
50+
const std::string &name,
51+
const std::string &pseudo)
52+
{
53+
return std::nullopt;
54+
}
3855
};
3956

4057
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,38 @@ void ViewTransitionModule::startViewTransitionEnd() {
138138
transitionStarted_ = false;
139139
}
140140

141+
std::optional<UIManagerViewTransitionDelegate::ViewTransitionInstance>
142+
ViewTransitionModule::getViewTransitionInstance(
143+
const std::string& name,
144+
const std::string& pseudo) {
145+
// Look up layout based on pseudo type ("old" or "new")
146+
if (pseudo == "new") {
147+
auto it = newLayout_.find(name);
148+
if (it != newLayout_.end()) {
149+
const auto& view = it->second;
150+
return ViewTransitionInstance{
151+
.x = view.layoutMetrics.originFromRoot.x,
152+
.y = view.layoutMetrics.originFromRoot.y,
153+
.width = view.layoutMetrics.size.width,
154+
.height = view.layoutMetrics.size.height,
155+
.nativeTag = view.tag};
156+
}
157+
} else if (pseudo == "old") {
158+
auto it = oldLayout_.find(name);
159+
if (it != oldLayout_.end()) {
160+
const auto& view = it->second;
161+
return ViewTransitionInstance{
162+
.x = view.layoutMetrics.originFromRoot.x,
163+
.y = view.layoutMetrics.originFromRoot.y,
164+
.width = view.layoutMetrics.size.width,
165+
.height = view.layoutMetrics.size.height,
166+
.nativeTag = view.tag};
167+
}
168+
}
169+
170+
return std::nullopt;
171+
}
172+
141173
void ViewTransitionModule::onTransitionAnimationEnd(
142174
const std::unordered_set<std::string>& names,
143175
Tag newTag,

packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class ViewTransitionModule : public UIManagerViewTransitionDelegate {
4545

4646
void startViewTransitionEnd() override;
4747

48+
std::optional<ViewTransitionInstance> getViewTransitionInstance(const std::string &name, const std::string &pseudo)
49+
override;
50+
4851
// Animation state structure for storing minimal view data
4952
struct AnimationKeyFrameViewLayoutMetrics {
5053
Point originFromRoot;

0 commit comments

Comments
 (0)