Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,10 @@ void UIManager::sendAccessibilityEvent(
}
}

UIManagerViewTransitionDelegate* UIManager::getViewTransitionDelegate() const {
return viewTransitionDelegate_;
}

void UIManager::configureNextLayoutAnimation(
jsi::Runtime& runtime,
const RawValue& config,
Expand Down Expand Up @@ -708,6 +712,13 @@ void UIManager::setNativeAnimatedDelegate(
nativeAnimatedDelegate_ = delegate;
}

void UIManager::setViewTransitionDelegate(
UIManagerViewTransitionDelegate* delegate) {
if (ReactNativeFeatureFlags::viewTransitionEnabled()) {
viewTransitionDelegate_ = delegate;
}
}

void UIManager::unstable_setAnimationBackend(
std::shared_ptr<UIManagerAnimationBackend> animationBackend) {
animationBackend_ = animationBackend;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <react/renderer/uimanager/UIManagerAnimationDelegate.h>
#include <react/renderer/uimanager/UIManagerDelegate.h>
#include <react/renderer/uimanager/UIManagerNativeAnimatedDelegate.h>
#include <react/renderer/uimanager/UIManagerViewTransitionDelegate.h>
#include <react/renderer/uimanager/consistency/LazyShadowTreeRevisionConsistencyManager.h>
#include <react/renderer/uimanager/consistency/ShadowTreeRevisionProvider.h>
#include <react/renderer/uimanager/primitives.h>
Expand Down Expand Up @@ -74,6 +75,12 @@ class UIManager final : public ShadowTreeDelegate {

void setNativeAnimatedDelegate(std::weak_ptr<UIManagerNativeAnimatedDelegate> delegate);

/**
* Sets and gets UIManager's ViewTransition API delegate.
*/
void setViewTransitionDelegate(UIManagerViewTransitionDelegate *delegate);
UIManagerViewTransitionDelegate *getViewTransitionDelegate() const;

void animationTick() const;

void synchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props);
Expand Down Expand Up @@ -242,6 +249,7 @@ class UIManager final : public ShadowTreeDelegate {
UIManagerDelegate *delegate_{};
UIManagerAnimationDelegate *animationDelegate_{nullptr};
std::weak_ptr<UIManagerNativeAnimatedDelegate> nativeAnimatedDelegate_;
UIManagerViewTransitionDelegate *viewTransitionDelegate_{nullptr};

const RuntimeExecutor runtimeExecutor_{};
ShadowTreeRegistry shadowTreeRegistry_{};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,256 @@ jsi::Value UIManagerBinding::get(
});
}

if (methodName == "measureInstance") {
auto paramCount = 1;
return jsi::Function::createFromHostFunction(
runtime,
name,
paramCount,
[uiManager, methodName, paramCount](
jsi::Runtime& runtime,
const jsi::Value& /*thisValue*/,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
validateArgumentCount(runtime, methodName, paramCount, count);

if (!arguments[0].isObject()) {
auto result = jsi::Object(runtime);
result.setProperty(runtime, "x", 0);
result.setProperty(runtime, "y", 0);
result.setProperty(runtime, "width", 0);
result.setProperty(runtime, "height", 0);
return result;
}

auto shadowNode = Bridging<std::shared_ptr<const ShadowNode>>::fromJs(
runtime, arguments[0]);

auto currentRevision =
uiManager->getShadowTreeRevisionProvider()->getCurrentRevision(
shadowNode->getSurfaceId());

if (currentRevision == nullptr) {
auto result = jsi::Object(runtime);
result.setProperty(runtime, "x", 0);
result.setProperty(runtime, "y", 0);
result.setProperty(runtime, "width", 0);
result.setProperty(runtime, "height", 0);
return result;
}

auto domRect = dom::getBoundingClientRect(
currentRevision, *shadowNode, true /* includeTransform */);

auto result = jsi::Object(runtime);
result.setProperty(runtime, "x", domRect.x);
result.setProperty(runtime, "y", domRect.y);
result.setProperty(runtime, "width", domRect.width);
result.setProperty(runtime, "height", domRect.height);

auto* viewTransitionDelegate = uiManager->getViewTransitionDelegate();
if (viewTransitionDelegate != nullptr) {
viewTransitionDelegate->captureLayoutMetricsFromRoot(shadowNode);
}

return result;
});
}

if (methodName == "applyViewTransitionName") {
auto paramCount = 3;
return jsi::Function::createFromHostFunction(
runtime,
name,
paramCount,
[uiManager, methodName, paramCount](
jsi::Runtime& runtime,
const jsi::Value& /*thisValue*/,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
validateArgumentCount(runtime, methodName, paramCount, count);

if (arguments[0].isObject()) {
auto shadowNode =
Bridging<std::shared_ptr<const ShadowNode>>::fromJs(
runtime, arguments[0]);
auto transitionName = arguments[1].isString()
? stringFromValue(runtime, arguments[1])
: "";
auto className = arguments[2].isString()
? stringFromValue(runtime, arguments[2])
: "";
if (!transitionName.empty()) {
auto* viewTransitionDelegate =
uiManager->getViewTransitionDelegate();
if (viewTransitionDelegate != nullptr) {
viewTransitionDelegate->applyViewTransitionName(
shadowNode, transitionName, className);
}
}
}

return jsi::Value::undefined();
});
}

if (methodName == "cancelViewTransitionName") {
auto paramCount = 2;
return jsi::Function::createFromHostFunction(
runtime,
name,
paramCount,
[uiManager, methodName, paramCount](
jsi::Runtime& runtime,
const jsi::Value& /*thisValue*/,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
validateArgumentCount(runtime, methodName, paramCount, count);

if (arguments[0].isObject()) {
auto shadowNode =
Bridging<std::shared_ptr<const ShadowNode>>::fromJs(
runtime, arguments[0]);
auto transitionName = arguments[1].isString()
? stringFromValue(runtime, arguments[1])
: "";
if (!transitionName.empty()) {
auto* viewTransitionDelegate =
uiManager->getViewTransitionDelegate();
if (viewTransitionDelegate != nullptr) {
viewTransitionDelegate->cancelViewTransitionName(
shadowNode, transitionName);
}
}
}

return jsi::Value::undefined();
});
}

if (methodName == "restoreViewTransitionName") {
auto paramCount = 1;
return jsi::Function::createFromHostFunction(
runtime,
name,
paramCount,
[uiManager, methodName, paramCount](
jsi::Runtime& runtime,
const jsi::Value& /*thisValue*/,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
validateArgumentCount(runtime, methodName, paramCount, count);

if (arguments[0].isObject()) {
auto shadowNode =
Bridging<std::shared_ptr<const ShadowNode>>::fromJs(
runtime, arguments[0]);
auto* viewTransitionDelegate =
uiManager->getViewTransitionDelegate();
if (viewTransitionDelegate != nullptr) {
viewTransitionDelegate->restoreViewTransitionName(shadowNode);
}
}

return jsi::Value::undefined();
});
}

if (methodName == "startViewTransition") {
auto paramCount = 1;
return jsi::Function::createFromHostFunction(
runtime,
name,
paramCount,
[uiManager, methodName, paramCount](
jsi::Runtime& runtime,
const jsi::Value& /*thisValue*/,
const jsi::Value* arguments,
size_t count) -> jsi::Value {
validateArgumentCount(runtime, methodName, paramCount, count);

auto* viewTransitionDelegate = uiManager->getViewTransitionDelegate();
if (viewTransitionDelegate == nullptr) {
return jsi::Value::undefined();
}

auto promiseConstructor =
runtime.global().getPropertyAsFunction(runtime, "Promise");

auto readyResolveFunc =
std::make_shared<std::shared_ptr<jsi::Function>>();
auto finishedResolveFunc =
std::make_shared<std::shared_ptr<jsi::Function>>();

auto mutationFunc = std::make_shared<jsi::Function>(
arguments[0].asObject(runtime).asFunction(runtime));

auto readyPromise = promiseConstructor.callAsConstructor(
runtime,
jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "readyExecutor"),
2,
[readyResolveFunc](
jsi::Runtime& runtime,
const jsi::Value& /*thisValue*/,
const jsi::Value* args,
size_t /*count*/) -> jsi::Value {
auto onReadyFunc = std::make_shared<jsi::Function>(
args[0].asObject(runtime).asFunction(runtime));
*readyResolveFunc = onReadyFunc;
return jsi::Value::undefined();
}));

auto finishedPromise = promiseConstructor.callAsConstructor(
runtime,
jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "finishedExecutor"),
2,
[finishedResolveFunc](
jsi::Runtime& rt,
const jsi::Value& /*thisValue*/,
const jsi::Value* args,
size_t /*count*/) -> jsi::Value {
auto onCompleteFunc = std::make_shared<jsi::Function>(
args[0].asObject(rt).asFunction(rt));
*finishedResolveFunc = onCompleteFunc;
return jsi::Value::undefined();
}));

auto result = jsi::Object(runtime);
result.setProperty(runtime, "ready", std::move(readyPromise));
result.setProperty(runtime, "finished", std::move(finishedPromise));

viewTransitionDelegate->startViewTransition(
[&runtime, mutationFunc = std::move(mutationFunc)]() {
mutationFunc->call(runtime);
},
[readyResolveFunc = std::move(readyResolveFunc), uiManager]() {
uiManager->runtimeExecutor_(
[readyResolveFunc =
readyResolveFunc](jsi::Runtime& rt) mutable {
if (*readyResolveFunc) {
(*readyResolveFunc)->call(rt);
}
});
},
[finishedResolveFunc = std::move(finishedResolveFunc),
uiManager]() {
uiManager->runtimeExecutor_(
[finishedResolveFunc =
finishedResolveFunc](jsi::Runtime& rt) mutable {
if (*finishedResolveFunc) {
(*finishedResolveFunc)->call(rt);
}
});
});

return jsi::Value(runtime, result);
});
}

return jsi::Value::undefined();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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.
*/

#pragma once

#include <react/renderer/core/ShadowNode.h>
#include <functional>

namespace facebook::react {

class UIManagerViewTransitionDelegate {
public:
virtual ~UIManagerViewTransitionDelegate() = default;

virtual void applyViewTransitionName(
const std::shared_ptr<const ShadowNode> &shadowNode,
const std::string &name,
const std::string &className)
{
}

virtual void cancelViewTransitionName(const std::shared_ptr<const ShadowNode> &shadowNode, const std::string &name) {}

virtual void restoreViewTransitionName(const std::shared_ptr<const ShadowNode> &shadowNode) {}

virtual void captureLayoutMetricsFromRoot(const std::shared_ptr<const ShadowNode> &shadowNode) {}

virtual void startViewTransition(
std::function<void()> mutationCallback,
std::function<void()> onReadyCallback,
std::function<void()> onCompleteCallback)
{
}
};

} // namespace facebook::react
Loading