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 a75c701 commit 61ea420
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"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": "patch",
"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 <JSValueComposition.h>
Expand Down Expand Up @@ -95,6 +96,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 @@ -163,6 +171,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
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
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ ComponentView::ComponentView(
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
ComponentViewFeatures flags)
: base_type(tag, reactContext), m_compContext(compContext), m_flags(flags) {
ComponentViewFeatures flags,
winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder)
: base_type(tag, reactContext, builder), m_compContext(compContext), m_flags(flags) {
m_outerVisual = compContext.CreateSpriteVisual(); // TODO could be a raw ContainerVisual if we had a
// CreateContainerVisual in ICompositionContext
}
Expand Down Expand Up @@ -916,24 +917,15 @@ ViewComponentView::ViewComponentView(
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
ComponentViewFeatures flags)
: base_type(compContext, tag, reactContext, flags),
ComponentViewFeatures flags,
winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder)
: base_type(compContext, tag, reactContext, flags, builder),
m_props(defaultProps ? defaultProps : ViewComponentView::defaultProps()) {}

winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ViewComponentView::createVisual() noexcept {
return m_compContext.CreateSpriteVisual();
}

void ViewComponentView::CreateVisualHandler(
const winrt::Microsoft::ReactNative::Composition::CreateVisualDelegate &handler) {
m_createVisualHandler = handler;
}

winrt::Microsoft::ReactNative::Composition::CreateVisualDelegate ViewComponentView::CreateVisualHandler()
const noexcept {
return m_createVisualHandler;
}

void ViewComponentView::CreateInternalVisualHandler(
const winrt::Microsoft::ReactNative::Composition::Experimental::CreateInternalVisualDelegate &handler) {
m_createInternalVisualHandler = handler;
Expand All @@ -948,10 +940,10 @@ void ViewComponentView::ensureVisual() noexcept {
if (!m_visual) {
if (m_createInternalVisualHandler) {
m_visual = m_createInternalVisualHandler(*this);
} else if (m_createVisualHandler) {
} else if (m_builder && m_builder->CreateVisualHandler()) {
m_visual =
winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::CreateVisual(
m_createVisualHandler(*this));
m_builder->CreateVisualHandler()(*this));
} else {
m_visual = createVisual();
}
Expand All @@ -969,6 +961,8 @@ winrt::Microsoft::ReactNative::ComponentView ViewComponentView::Create(

winrt::Microsoft::ReactNative::Composition::Experimental::IVisual
ViewComponentView::VisualToMountChildrenInto() noexcept {
if (m_builder && m_builder->VisualToMountChildrenIntoHandler())
return m_builder->VisualToMountChildrenIntoHandler()(*this);
return Visual();
}

Expand Down Expand Up @@ -1216,7 +1210,7 @@ winrt::Microsoft::ReactNative::ViewProps ViewComponentView::ViewProps() noexcept

winrt::Microsoft::ReactNative::ViewProps ViewComponentView::ViewPropsInner() noexcept {
// If we have AbiViewProps, then we dont need to new up a props wrapper
if (m_customComponent) {
if (m_builder) {
const auto &abiViewProps = *std::static_pointer_cast<const ::Microsoft::ReactNative::AbiViewProps>(m_props);
return abiViewProps.ViewProps();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ struct ComponentView : public ComponentViewT<
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
ComponentViewFeatures flags);
ComponentViewFeatures flags,
winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder);
virtual ~ComponentView();

virtual winrt::Microsoft::ReactNative::Composition::Experimental::IVisual Visual() const noexcept {
Expand Down Expand Up @@ -208,7 +209,8 @@ struct ViewComponentView : public ViewComponentViewT<
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
ComponentViewFeatures flags);
ComponentViewFeatures flags,
winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder = nullptr);

virtual winrt::Microsoft::ReactNative::Composition::Experimental::IVisual createVisual() noexcept;

Expand All @@ -226,7 +228,6 @@ struct ViewComponentView : public ViewComponentViewT<
bool m_hasNonVisualChildren{false};
facebook::react::SharedViewProps m_props;
winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_visual{nullptr};
winrt::Microsoft::ReactNative::Composition::CreateVisualDelegate m_createVisualHandler{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::CreateInternalVisualDelegate m_createInternalVisualHandler{
nullptr};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@ namespace winrt::Microsoft::ReactNative::Composition::implementation {
ContentIslandComponentView::ContentIslandComponentView(
const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext)
: base_type(ViewComponentView::defaultProps(), compContext, tag, reactContext, ComponentViewFeatures::Default) {
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
ReactCompositionViewComponentBuilder *builder)
: base_type(
ViewComponentView::defaultProps(),
compContext,
tag,
reactContext,
ComponentViewFeatures::Default,
builder) {
m_mountedToken = Mounted([](const winrt::IInspectable &, const winrt::Microsoft::ReactNative::ComponentView &view) {
view.as<ContentIslandComponentView>()->OnMounted();
});
Expand Down
Loading

0 comments on commit 61ea420

Please sign in to comment.