Skip to content

Commit

Permalink
Add ability to override UpdateLayoutMetrics and VisualToMountChildren…
Browse files Browse the repository at this point in the history
…Into (microsoft#14182)

* Add ability to override UpdateLayoutMetrics and VisualToMountChildrenInto

* Change files

* format

* fix
  • Loading branch information
acoates-ms committed Dec 9, 2024
1 parent e25fa5a commit 8469ad2
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add ability to override UpdateLayoutMetrics and VisualToMountChildrenInto",
"packageName": "@react-native-windows/codegen",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add ability to override UpdateLayoutMetrics and VisualToMountChildrenInto",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type FilesOutput = Map<string, string>;
const headerTemplate = `/*
* This file is auto-generated from ::_COMPONENT_NAME_::NativeComponent spec file in flow / TypeScript.
*/
// clang-format off
#pragma once
#include <NativeModules.h>
Expand Down Expand Up @@ -99,6 +100,13 @@ struct Base::_COMPONENT_NAME_:: {
m_props = newProps;
}
// UpdateLayoutMetrics will only be called if this method is overridden
virtual void UpdateLayoutMetrics(
const winrt::Microsoft::ReactNative::ComponentView &/*view*/,
const winrt::Microsoft::ReactNative::LayoutMetrics &/*newLayoutMetrics*/,
const winrt::Microsoft::ReactNative::LayoutMetrics &/*oldLayoutMetrics*/) noexcept {
}
// UpdateState will only be called if this method is overridden
virtual void UpdateState(
const winrt::Microsoft::ReactNative::ComponentView &/*view*/,
Expand Down Expand Up @@ -167,6 +175,13 @@ void Register::_COMPONENT_NAME_::NativeComponent(
userData->UpdateProps(view, newProps ? newProps.as<::_COMPONENT_NAME_::Props>() : nullptr, oldProps ? oldProps.as<::_COMPONENT_NAME_::Props>() : nullptr);
});
compBuilder.SetUpdateLayoutMetricsHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::LayoutMetrics &newLayoutMetrics,
const winrt::Microsoft::ReactNative::LayoutMetrics &oldLayoutMetrics) noexcept {
auto userData = view.UserData().as<TUserData>();
userData->UpdateLayoutMetrics(view, newLayoutMetrics, oldLayoutMetrics);
});
builder.SetUpdateEventEmitterHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::EventEmitter &eventEmitter) noexcept {
auto userData = view.UserData().as<TUserData>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/*
* This file is auto-generated from DrawingIslandNativeComponent spec file in flow / TypeScript.
*/
// clang-format off
#pragma once

#include <NativeModules.h>
Expand Down Expand Up @@ -53,6 +54,13 @@ struct BaseDrawingIsland {
m_props = newProps;
}

// UpdateLayoutMetrics will only be called if this method is overridden
virtual void UpdateLayoutMetrics(
const winrt::Microsoft::ReactNative::ComponentView &/*view*/,
const winrt::Microsoft::ReactNative::LayoutMetrics &/*newLayoutMetrics*/,
const winrt::Microsoft::ReactNative::LayoutMetrics &/*oldLayoutMetrics*/) noexcept {
}

// UpdateState will only be called if this method is overridden
virtual void UpdateState(
const winrt::Microsoft::ReactNative::ComponentView &/*view*/,
Expand Down Expand Up @@ -117,6 +125,13 @@ void RegisterDrawingIslandNativeComponent(
userData->UpdateProps(view, newProps ? newProps.as<DrawingIslandProps>() : nullptr, oldProps ? oldProps.as<DrawingIslandProps>() : nullptr);
});

compBuilder.SetUpdateLayoutMetricsHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::LayoutMetrics &newLayoutMetrics,
const winrt::Microsoft::ReactNative::LayoutMetrics &oldLayoutMetrics) noexcept {
auto userData = view.UserData().as<TUserData>();
userData->UpdateLayoutMetrics(view, newLayoutMetrics, oldLayoutMetrics);
});

builder.SetUpdateEventEmitterHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::EventEmitter &eventEmitter) noexcept {
auto userData = view.UserData().as<TUserData>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/*
* This file is auto-generated from MovingLightNativeComponent spec file in flow / TypeScript.
*/
// clang-format off
#pragma once

#include <NativeModules.h>
Expand Down Expand Up @@ -94,6 +95,13 @@ struct BaseMovingLight {
m_props = newProps;
}

// UpdateLayoutMetrics will only be called if this method is overridden
virtual void UpdateLayoutMetrics(
const winrt::Microsoft::ReactNative::ComponentView &/*view*/,
const winrt::Microsoft::ReactNative::LayoutMetrics &/*newLayoutMetrics*/,
const winrt::Microsoft::ReactNative::LayoutMetrics &/*oldLayoutMetrics*/) noexcept {
}

// UpdateState will only be called if this method is overridden
virtual void UpdateState(
const winrt::Microsoft::ReactNative::ComponentView &/*view*/,
Expand Down Expand Up @@ -170,6 +178,13 @@ void RegisterMovingLightNativeComponent(
userData->UpdateProps(view, newProps ? newProps.as<MovingLightProps>() : nullptr, oldProps ? oldProps.as<MovingLightProps>() : nullptr);
});

compBuilder.SetUpdateLayoutMetricsHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::LayoutMetrics &newLayoutMetrics,
const winrt::Microsoft::ReactNative::LayoutMetrics &oldLayoutMetrics) noexcept {
auto userData = view.UserData().as<TUserData>();
userData->UpdateLayoutMetrics(view, newLayoutMetrics, oldLayoutMetrics);
});

builder.SetUpdateEventEmitterHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::EventEmitter &eventEmitter) noexcept {
auto userData = view.UserData().as<TUserData>();
Expand Down
72 changes: 26 additions & 46 deletions vnext/Microsoft.ReactNative/Fabric/ComponentView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ struct RootComponentView;

namespace winrt::Microsoft::ReactNative::implementation {

ComponentView::ComponentView(facebook::react::Tag tag, winrt::Microsoft::ReactNative::ReactContext const &reactContext)
: m_tag(tag), m_reactContext(reactContext) {}

void ComponentView::MarkAsCustomComponent() noexcept {
m_customComponent = true;
ComponentView::ComponentView(
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder)
: m_tag(tag), m_reactContext(reactContext) {
m_builder.copy_from(builder);
}

std::vector<facebook::react::ComponentDescriptorProvider>
Expand All @@ -52,18 +53,15 @@ void ComponentView::MountChildComponentView(
uint32_t index) noexcept {
m_children.InsertAt(index, childComponentView);
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->parent(*this);
if (m_mountChildComponentViewHandler) {
m_mountChildComponentViewHandler(*this, winrt::make<MountChildComponentViewArgs>(childComponentView, index));
if (m_builder && m_builder->MountChildComponentViewHandler()) {
m_builder->MountChildComponentViewHandler()(
*this, winrt::make<MountChildComponentViewArgs>(childComponentView, index));
}
if (m_mounted) {
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->onMounted();
}
}

void ComponentView::MountChildComponentViewHandler(const MountChildComponentViewDelegate &handler) noexcept {
m_mountChildComponentViewHandler = handler;
}

void ComponentView::onMounted() noexcept {
assert(!m_mounted);
m_mounted = true;
Expand All @@ -89,16 +87,14 @@ void ComponentView::Mounted(winrt::event_token const &token) noexcept {
void ComponentView::UnmountChildComponentView(
const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
uint32_t index) noexcept {
if (m_mountChildComponentViewHandler) {
m_mountChildComponentViewHandler(*this, winrt::make<MountChildComponentViewArgs>(childComponentView, index));
if (m_builder && m_builder->UnmountChildComponentViewHandler()) {
m_builder->UnmountChildComponentViewHandler()(
*this, winrt::make<UnmountChildComponentViewArgs>(childComponentView, index));
}
m_children.RemoveAt(index);
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->parent(nullptr);
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(childComponentView)->onUnmounted();
}
void ComponentView::UnmountChildComponentViewHandler(const UnmountChildComponentViewDelegate &handler) noexcept {
m_unmountChildComponentViewHandler = handler;
}

void ComponentView::onUnmounted() noexcept {
if (!m_mounted)
Expand Down Expand Up @@ -148,15 +144,11 @@ uint32_t UnmountChildComponentViewArgs::Index() const noexcept {
void ComponentView::updateProps(
facebook::react::Props::Shared const &props,
facebook::react::Props::Shared const &oldProps) noexcept {
if (m_updatePropsDelegate) {
m_updatePropsDelegate(*this, userProps(props), oldProps ? userProps(oldProps) : nullptr);
if (m_builder && m_builder->UpdatePropsHandler()) {
m_builder->UpdatePropsHandler()(*this, userProps(props), oldProps ? userProps(oldProps) : nullptr);
}
}

void ComponentView::UpdatePropsHandler(const UpdatePropsDelegate &handler) noexcept {
m_updatePropsDelegate = handler;
}

const winrt::Microsoft::ReactNative::IComponentProps ComponentView::userProps(
facebook::react::Props::Shared const &props) noexcept {
const auto &abiProps =
Expand All @@ -165,28 +157,20 @@ const winrt::Microsoft::ReactNative::IComponentProps ComponentView::userProps(
}

void ComponentView::updateEventEmitter(facebook::react::EventEmitter::Shared const &eventEmitter) noexcept {
if (m_updateEventEmitterHandler) {
m_updateEventEmitterHandler(*this, winrt::make<EventEmitter>(eventEmitter));
if (m_builder && m_builder->UpdateEventEmitterHandler()) {
m_builder->UpdateEventEmitterHandler()(*this, winrt::make<EventEmitter>(eventEmitter));
}
}

void ComponentView::UpdateEventEmitterHandler(const UpdateEventEmitterDelegate &handler) noexcept {
m_updateEventEmitterHandler = handler;
}

void ComponentView::updateState(
facebook::react::State::Shared const &state,
facebook::react::State::Shared const &oldState) noexcept {
// Avoid new-ing up a new AbiComponentState on every state change if we are not a custom component
if (m_updateStateDelegate) {
m_updateStateDelegate(*this, winrt::make<::Microsoft::ReactNative::AbiComponentState>(state));
if (m_builder && m_builder->UpdateStateHandler()) {
m_builder->UpdateStateHandler()(*this, winrt::make<::Microsoft::ReactNative::AbiComponentState>(state));
}
}

void ComponentView::UpdateStateHandler(const UpdateStateDelegate &handler) noexcept {
m_updateStateDelegate = handler;
}

LayoutMetricsChangedArgs::LayoutMetricsChangedArgs(
const winrt::Microsoft::ReactNative::LayoutMetrics &newLayoutMetrics,
const winrt::Microsoft::ReactNative::LayoutMetrics &oldLayoutMetrics)
Expand Down Expand Up @@ -216,6 +200,10 @@ void ComponentView::updateLayoutMetrics(
layoutMetrics.frame.size.height},
layoutMetrics.pointScaleFactor};

if (m_builder && m_builder->UpdateLayoutMetricsHandler()) {
m_builder->UpdateLayoutMetricsHandler()(*this, newMetrics, oldMetrics);
}

m_layoutMetrics = layoutMetrics;

m_layoutMetricsChangedEvent(*this, winrt::make<LayoutMetricsChangedArgs>(newMetrics, oldMetrics));
Expand All @@ -240,13 +228,9 @@ void ComponentView::LayoutMetricsChanged(winrt::event_token const &token) noexce
m_layoutMetricsChangedEvent.remove(token);
}

void ComponentView::FinalizeUpdateHandler(const UpdateFinalizerDelegate &handler) noexcept {
m_finalizeUpdateHandler = handler;
}

void ComponentView::FinalizeUpdates(winrt::Microsoft::ReactNative::ComponentViewUpdateMask updateMask) noexcept {
if (m_finalizeUpdateHandler) {
m_finalizeUpdateHandler(*this, updateMask);
if (m_builder && m_builder->FinalizeUpdateHandler()) {
m_builder->FinalizeUpdateHandler()(*this, updateMask);
}
}

Expand All @@ -257,13 +241,9 @@ facebook::react::Props::Shared ComponentView::props() noexcept {
return {};
}

void ComponentView::CustomCommandHandler(const HandleCommandDelegate &handler) noexcept {
m_customCommandHandler = handler;
}

void ComponentView::HandleCommand(const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept {
if (m_customCommandHandler) {
m_customCommandHandler(*this, args);
if (m_builder && m_builder->CustomCommandHandler()) {
m_builder->CustomCommandHandler()(*this, args);
}
}

Expand Down
25 changes: 6 additions & 19 deletions vnext/Microsoft.ReactNative/Fabric/ComponentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <react/renderer/core/LayoutMetrics.h>

#include <ComponentView.Experimental.interop.h>
#include <Fabric/Composition/ReactCompositionViewComponentBuilder.h>
#include <Fabric/Composition/Theme.h>
#include <uiautomationcore.h>
#include <winrt/Microsoft.ReactNative.Composition.Input.h>
Expand Down Expand Up @@ -80,7 +81,10 @@ struct UnmountChildComponentViewArgs : public UnmountChildComponentViewArgsT<Unm

struct ComponentView
: public ComponentViewT<ComponentView, ::Microsoft::ReactNative::Composition::Experimental::IComponentViewInterop> {
ComponentView(facebook::react::Tag tag, winrt::Microsoft::ReactNative::ReactContext const &reactContext);
ComponentView(
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder);

virtual std::vector<facebook::react::ComponentDescriptorProvider> supplementalComponentDescriptorProviders() noexcept;
virtual void updateProps(
Expand Down Expand Up @@ -115,7 +119,6 @@ struct ComponentView
virtual void onGettingFocus(const winrt::Microsoft::ReactNative::GettingFocusEventArgs &args) noexcept;
virtual void onLostFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept;
virtual void onGotFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept;
void MarkAsCustomComponent() noexcept;
virtual void onMounted() noexcept;
bool isMounted() noexcept;
virtual void onUnmounted() noexcept;
Expand Down Expand Up @@ -223,14 +226,6 @@ struct ComponentView
void UserData(const winrt::IInspectable &userData) noexcept;
winrt::IInspectable UserData() const noexcept;

void CustomCommandHandler(const HandleCommandDelegate &handler) noexcept;
void UpdatePropsHandler(const UpdatePropsDelegate &handler) noexcept;
void UpdateStateHandler(const UpdateStateDelegate &handler) noexcept;
void UpdateEventEmitterHandler(const UpdateEventEmitterDelegate &handler) noexcept;
void MountChildComponentViewHandler(const MountChildComponentViewDelegate &handler) noexcept;
void UnmountChildComponentViewHandler(const UnmountChildComponentViewDelegate &handler) noexcept;
void FinalizeUpdateHandler(const UpdateFinalizerDelegate &handler) noexcept;

virtual void MountChildComponentView(
const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
uint32_t index) noexcept;
Expand Down Expand Up @@ -258,7 +253,7 @@ struct ComponentView
const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept;

protected:
bool m_customComponent : 1 {false}; // Is a user custom component, and so needs to call external override functions
winrt::com_ptr<winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder> m_builder;
bool m_mounted : 1 {false};
const facebook::react::Tag m_tag;
winrt::IInspectable m_userData;
Expand All @@ -270,14 +265,6 @@ struct ComponentView
winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::ReactNative::ComponentView> m_children{
winrt::single_threaded_vector<winrt::Microsoft::ReactNative::ComponentView>()};

UpdatePropsDelegate m_updatePropsDelegate{nullptr};
UpdateStateDelegate m_updateStateDelegate{nullptr};
HandleCommandDelegate m_customCommandHandler{nullptr};
UpdateFinalizerDelegate m_finalizeUpdateHandler{nullptr};
MountChildComponentViewDelegate m_mountChildComponentViewHandler{nullptr};
UnmountChildComponentViewDelegate m_unmountChildComponentViewHandler{nullptr};
UpdateEventEmitterDelegate m_updateEventEmitterHandler{nullptr};

winrt::event<
winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs>>
m_keyDownEvent;
Expand Down
Loading

0 comments on commit 8469ad2

Please sign in to comment.