Skip to content

Commit

Permalink
Fix issue with prop cloning with custom native props (#14061)
Browse files Browse the repository at this point in the history
* Fix issue with prop cloning with custom native props

* format

* prettier

* Change files

---------

Co-authored-by: React-Native-Windows Bot <[email protected]>
  • Loading branch information
acoates-ms and rnbot authored Nov 2, 2024
1 parent 9da7ddb commit 59443c8
Show file tree
Hide file tree
Showing 18 changed files with 134 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Fix issue with prop cloning with custom native props",
"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": "Fix issue with prop cloning with custom native props",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ const headerTemplate = `/*

const propsTemplate = `REACT_STRUCT(::_PROPS_NAME_::)
struct ::_PROPS_NAME_:: : winrt::implements<::_PROPS_NAME_::, winrt::Microsoft::ReactNative::IComponentProps> {
::_PROPS_NAME_::(winrt::Microsoft::ReactNative::ViewProps props) : ViewProps(props) {}
::_PROPS_NAME_::(winrt::Microsoft::ReactNative::ViewProps props, const winrt::Microsoft::ReactNative::IComponentProps& cloneFrom)
: ViewProps(props)
{
if (cloneFrom) {
auto cloneFromProps = cloneFrom.as<::_PROPS_NAME_::>();
::_PROP_INITIALIZERS_::
}
}
void SetProp(uint32_t hash, winrt::hstring propName, winrt::Microsoft::ReactNative::IJSValueReader value) noexcept {
winrt::Microsoft::ReactNative::ReadProp(hash, propName, value, *this);
Expand Down Expand Up @@ -144,8 +151,10 @@ void Register::_COMPONENT_NAME_::NativeComponent(
L"::_COMPONENT_NAME_::", [builderCallback](winrt::Microsoft::ReactNative::IReactViewComponentBuilder const &builder) noexcept {
auto compBuilder = builder.as<winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder>();
builder.SetCreateProps(
[](winrt::Microsoft::ReactNative::ViewProps props) noexcept { return winrt::make<::_COMPONENT_NAME_::Props>(props); });
builder.SetCreateProps([](winrt::Microsoft::ReactNative::ViewProps props,
const winrt::Microsoft::ReactNative::IComponentProps& cloneFrom) noexcept {
return winrt::make<::_COMPONENT_NAME_::Props>(props, cloneFrom);
});
builder.SetUpdatePropsHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::IComponentProps &newProps,
Expand Down Expand Up @@ -296,6 +305,12 @@ export function createComponentGenerator({
})
.join('\n');

const propInitializers = componentShape.props
.map(prop => {
return ` ${prop.name} = cloneFromProps->${prop.name};`;
})
.join('\n');

const propObjectTypes = propObjectAliases.jobs
.map(propObjectTypeName => {
const propObjectType = propObjectAliases.types[propObjectTypeName]!;
Expand Down Expand Up @@ -510,6 +525,7 @@ ${
.replace(/::_EVENT_EMITTER_NAME_::/g, eventEmitterName)
.replace(/::_PROPS_NAME_::/g, propsName)
.replace(/::_COMPONENT_NAME_::/g, componentName)
.replace(/::_PROP_INITIALIZERS_::/g, propInitializers)
.replace(/::_PROPS_FIELDS_::/g, propsFields)
.replace(/::_NAMESPACE_::/g, namespace)
.replace(/\n\n\n+/g, '\n\n');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ namespace winrt::PlaygroundApp::implementation {
REACT_STRUCT(CustomXamlComponentProps)
struct CustomXamlComponentProps
: winrt::implements<CustomXamlComponentProps, winrt::Microsoft::ReactNative::IComponentProps> {
CustomXamlComponentProps(winrt::Microsoft::ReactNative::ViewProps props) : m_props(props) {}
CustomXamlComponentProps(
winrt::Microsoft::ReactNative::ViewProps props,
const winrt::Microsoft::ReactNative::IComponentProps &cloneFrom)
: m_props(props) {
if (cloneFrom) {
auto cloneFromProps = cloneFrom.as<CustomXamlComponentProps>();
label = cloneFromProps->label;
}
}

void SetProp(uint32_t hash, winrt::hstring propName, winrt::Microsoft::ReactNative::IJSValueReader value) noexcept {
winrt::Microsoft::ReactNative::ReadProp(hash, propName, value, *this);
Expand Down Expand Up @@ -139,8 +147,9 @@ struct CustomComponentUserData : winrt::implements<CustomComponentUserData, winr
static void ConfigureBuilderForCustomComponent(
winrt::Microsoft::ReactNative::IReactViewComponentBuilder const &builder,
bool nativeLayout) {
builder.SetCreateProps([](winrt::Microsoft::ReactNative::ViewProps props) noexcept {
return winrt::make<CustomXamlComponentProps>(props);
builder.SetCreateProps([](winrt::Microsoft::ReactNative::ViewProps props,
const winrt::Microsoft::ReactNative::IComponentProps &cloneFrom) noexcept {
return winrt::make<CustomXamlComponentProps>(props, cloneFrom);
});

builder.SetFinalizeUpdateHandler([](const winrt::Microsoft::ReactNative::ComponentView &source,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ namespace winrt::SampleCustomComponent::Codegen {

REACT_STRUCT(DrawingIslandProps)
struct DrawingIslandProps : winrt::implements<DrawingIslandProps, winrt::Microsoft::ReactNative::IComponentProps> {
DrawingIslandProps(winrt::Microsoft::ReactNative::ViewProps props) : ViewProps(props) {}
DrawingIslandProps(winrt::Microsoft::ReactNative::ViewProps props, const winrt::Microsoft::ReactNative::IComponentProps& cloneFrom)
: ViewProps(props)
{
if (cloneFrom) {
auto cloneFromProps = cloneFrom.as<DrawingIslandProps>();

}
}

void SetProp(uint32_t hash, winrt::hstring propName, winrt::Microsoft::ReactNative::IJSValueReader value) noexcept {
winrt::Microsoft::ReactNative::ReadProp(hash, propName, value, *this);
Expand Down Expand Up @@ -92,8 +99,10 @@ void RegisterDrawingIslandNativeComponent(
L"DrawingIsland", [builderCallback](winrt::Microsoft::ReactNative::IReactViewComponentBuilder const &builder) noexcept {
auto compBuilder = builder.as<winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder>();

builder.SetCreateProps(
[](winrt::Microsoft::ReactNative::ViewProps props) noexcept { return winrt::make<DrawingIslandProps>(props); });
builder.SetCreateProps([](winrt::Microsoft::ReactNative::ViewProps props,
const winrt::Microsoft::ReactNative::IComponentProps& cloneFrom) noexcept {
return winrt::make<DrawingIslandProps>(props, cloneFrom);
});

builder.SetUpdatePropsHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::IComponentProps &newProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,17 @@ struct MovingLightSpec_MovingLightProps_objectProp {

REACT_STRUCT(MovingLightProps)
struct MovingLightProps : winrt::implements<MovingLightProps, winrt::Microsoft::ReactNative::IComponentProps> {
MovingLightProps(winrt::Microsoft::ReactNative::ViewProps props) : ViewProps(props) {}
MovingLightProps(winrt::Microsoft::ReactNative::ViewProps props, const winrt::Microsoft::ReactNative::IComponentProps& cloneFrom)
: ViewProps(props)
{
if (cloneFrom) {
auto cloneFromProps = cloneFrom.as<MovingLightProps>();
size = cloneFromProps->size;
color = cloneFromProps->color;
eventParam = cloneFromProps->eventParam;
objectProp = cloneFromProps->objectProp;
}
}

void SetProp(uint32_t hash, winrt::hstring propName, winrt::Microsoft::ReactNative::IJSValueReader value) noexcept {
winrt::Microsoft::ReactNative::ReadProp(hash, propName, value, *this);
Expand Down Expand Up @@ -142,8 +152,10 @@ void RegisterMovingLightNativeComponent(
L"MovingLight", [builderCallback](winrt::Microsoft::ReactNative::IReactViewComponentBuilder const &builder) noexcept {
auto compBuilder = builder.as<winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder>();

builder.SetCreateProps(
[](winrt::Microsoft::ReactNative::ViewProps props) noexcept { return winrt::make<MovingLightProps>(props); });
builder.SetCreateProps([](winrt::Microsoft::ReactNative::ViewProps props,
const winrt::Microsoft::ReactNative::IComponentProps& cloneFrom) noexcept {
return winrt::make<MovingLightProps>(props, cloneFrom);
});

builder.SetUpdatePropsHandler([](const winrt::Microsoft::ReactNative::ComponentView &view,
const winrt::Microsoft::ReactNative::IComponentProps &newProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ struct MovingLight : public winrt::implements<MovingLight, winrt::IInspectable>,
auto view = sender.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();
if (!oldProps || oldProps->color != newProps->color) {
m_spotlight.InnerConeColor(newProps->color.AsWindowsColor(view.Theme()));
} else {
m_spotlight.InnerConeColor(winrt::Windows::UI::Colors::FloralWhite());
}

if (!oldProps || oldProps->size != newProps->size) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,10 @@ facebook::react::Props::Shared AbiComponentDescriptor::cloneProps(
rawProps);
auto userProps =
winrt::get_self<winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder>(m_builder)
->CreateProps(nullptr);
->CreateProps(
nullptr,
props ? static_cast<winrt::Microsoft::ReactNative::implementation::AbiProps const &>(*props).UserProps()
: nullptr);
shadowNodeProps->SetUserProps(userProps);

const auto &dynamic = static_cast<folly::dynamic>(rawProps);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ facebook::react::Props::Shared AbiViewComponentDescriptor::cloneProps(
winrt::make<winrt::Microsoft::ReactNative::implementation::ViewProps>(shadowNodeProps, false /*holdRef*/);
auto userProps =
winrt::get_self<winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder>(m_builder)
->CreateProps(viewProps);
->CreateProps(viewProps, props ? static_cast<AbiViewProps const &>(*props).UserProps() : nullptr);
shadowNodeProps->SetUserProps(userProps, viewProps);

const auto &dynamic = static_cast<folly::dynamic>(rawProps);
Expand Down
7 changes: 7 additions & 0 deletions vnext/Microsoft.ReactNative/Fabric/AbiViewProps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IBrush Color::AsIntern
return winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::Theme>(theme)->Brush(*m_color);
}

bool Color::Equals(const winrt::Microsoft::ReactNative::Color &color) const noexcept {
if (!color) {
return false;
}
return m_color == winrt::get_self<Color>(color)->m_color;
}

winrt::Microsoft::ReactNative::Color Color::ReadValue(
const winrt::Microsoft::ReactNative::IJSValueReader &reader) noexcept {
switch (reader.ValueType()) {
Expand Down
2 changes: 2 additions & 0 deletions vnext/Microsoft.ReactNative/Fabric/AbiViewProps.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ struct Color : ColorT<Color, Composition::Experimental::IInternalColor> {
winrt::Microsoft::ReactNative::Composition::Experimental::IBrush AsInternalBrush(
const winrt::Microsoft::ReactNative::Composition::Theme theme) noexcept;

bool Equals(const winrt::Microsoft::ReactNative::Color &color) const noexcept;

static winrt::Microsoft::ReactNative::Color ReadValue(
const winrt::Microsoft::ReactNative::IJSValueReader &reader) noexcept;
static void WriteValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,10 @@ void ComponentView::ReleasePointerCapture(
->ReleasePointerCapture(pointer, static_cast<facebook::react::Tag>(Tag()));
}

void ComponentView::SetViewFeatures(ComponentViewFeatures viewFeatures) noexcept {
m_flags = viewFeatures;
}

RECT ComponentView::getClientRect() const noexcept {
RECT rc{0};
facebook::react::Point parentOffset{0};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct ComponentView : public ComponentViewT<
void onGotFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept override;
bool CapturePointer(const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer) noexcept;
void ReleasePointerCapture(const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer) noexcept;
void SetViewFeatures(ComponentViewFeatures viewFeatures) noexcept;

std::vector<facebook::react::ComponentDescriptorProvider> supplementalComponentDescriptorProviders() noexcept
override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ void ReactCompositionViewComponentBuilder::SetCreateProps(ViewPropsFactory impl)
m_propsFactory = impl;
}

IComponentProps ReactCompositionViewComponentBuilder::CreateProps(ViewProps props) noexcept {
return m_propsFactory(props);
IComponentProps ReactCompositionViewComponentBuilder::CreateProps(
ViewProps props,
const IComponentProps &cloneFrom) noexcept {
return m_propsFactory(props, cloneFrom);
}

void ReactCompositionViewComponentBuilder::CreateShadowNode(ShadowNode shadowNode) noexcept {
Expand Down Expand Up @@ -72,27 +74,32 @@ void ReactCompositionViewComponentBuilder::InitializeComponentView(

void ReactCompositionViewComponentBuilder::SetComponentViewInitializer(
const ComponentViewInitializer &initializer) noexcept {
m_fnCreateView =
[initializer](const IReactContext &reactContext, int32_t tag, const Experimental::ICompositionContext &context) {
auto view = winrt::make<winrt::Microsoft::ReactNative::implementation::ComponentView>(tag, reactContext);
initializer(view);
return view;
};
m_fnCreateView = [initializer](
const IReactContext &reactContext,
int32_t tag,
const Experimental::ICompositionContext &context,
ComponentViewFeatures) {
auto view = winrt::make<winrt::Microsoft::ReactNative::implementation::ComponentView>(tag, reactContext);
initializer(view);
return view;
};
m_descriptorConstructorFactory = []() {
return &facebook::react::concreteComponentDescriptorConstructor<::Microsoft::ReactNative::AbiComponentDescriptor>;
};
}

void ReactCompositionViewComponentBuilder::SetViewComponentViewInitializer(
const ViewComponentViewInitializer &initializer) noexcept {
m_fnCreateView =
[initializer](const IReactContext &reactContext, int32_t tag, const Experimental::ICompositionContext &context) {
auto view = winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView::Create(
context, tag, reactContext)
.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();
initializer(view);
return view;
};
m_fnCreateView = [initializer](
const IReactContext &reactContext,
int32_t tag,
const Experimental::ICompositionContext &context,
ComponentViewFeatures features) {
auto view = winrt::make<implementation::ViewComponentView>(
implementation::ViewComponentView::defaultProps(), context, tag, reactContext, features);
initializer(view);
return view;
};
m_descriptorConstructorFactory = []() {
return &facebook::react::concreteComponentDescriptorConstructor<
::Microsoft::ReactNative::AbiViewComponentDescriptor>;
Expand All @@ -101,9 +108,12 @@ void ReactCompositionViewComponentBuilder::SetViewComponentViewInitializer(

void ReactCompositionViewComponentBuilder::SetContentIslandComponentViewInitializer(
const ComponentIslandComponentViewInitializer &initializer) noexcept {
m_fnCreateView = [initializer](
const IReactContext &reactContext, int32_t tag, const Experimental::ICompositionContext &context)
-> winrt::Microsoft::ReactNative::Composition::ContentIslandComponentView {
m_fnCreateView =
[initializer](
const IReactContext &reactContext,
int32_t tag,
const Experimental::ICompositionContext &context,
ComponentViewFeatures) -> winrt::Microsoft::ReactNative::Composition::ContentIslandComponentView {
auto view = winrt::make<winrt::Microsoft::ReactNative::Composition::implementation::ContentIslandComponentView>(
context, tag, reactContext);
initializer(view);
Expand Down Expand Up @@ -186,12 +196,16 @@ void ReactCompositionViewComponentBuilder::SetCreateVisualHandler(CreateVisualDe
m_createVisualHandler = impl;
}

void ReactCompositionViewComponentBuilder::SetViewFeatures(ComponentViewFeatures viewFeatures) noexcept {
m_features = viewFeatures;
}

winrt::Microsoft::ReactNative::ComponentView ReactCompositionViewComponentBuilder::CreateView(
const IReactContext &reactContext,
int32_t tag,
const Experimental::ICompositionContext &context) noexcept {
assert(m_fnCreateView);
auto view = m_fnCreateView(reactContext, tag, context);
auto view = m_fnCreateView(reactContext, tag, context, m_features);
InitializeComponentView(view);
return view;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ struct ReactCompositionViewComponentBuilder : winrt::implements<
public: // Composition::IReactCompositionViewComponentBuilder
void SetViewComponentViewInitializer(const ViewComponentViewInitializer &initializer) noexcept;
void SetContentIslandComponentViewInitializer(const ComponentIslandComponentViewInitializer &initializer) noexcept;

void SetCreateVisualHandler(CreateVisualDelegate impl) noexcept;
void SetViewFeatures(ComponentViewFeatures viewFeatures) noexcept;

public:
IComponentProps CreateProps(ViewProps props) noexcept;
IComponentProps CreateProps(ViewProps props, const IComponentProps &cloneFrom) noexcept;
void CreateShadowNode(ShadowNode shadowNode) noexcept;
void CloneShadowNode(ShadowNode shadowNode, ShadowNode sourceShadowNode) noexcept;
winrt::Windows::Foundation::IInspectable InitialStateData(
Expand All @@ -69,10 +69,12 @@ struct ReactCompositionViewComponentBuilder : winrt::implements<
InitialStateDataFactory m_initialStateDataFactory;
winrt::Microsoft::ReactNative::MeasureContentHandler m_measureContent;
winrt::Microsoft::ReactNative::LayoutHandler m_layoutHandler;
ComponentViewFeatures m_features{ComponentViewFeatures::Default};
std::function<winrt::Microsoft::ReactNative::ComponentView(
const IReactContext &reactContext,
int32_t tag,
const Experimental::ICompositionContext &context)>
const Experimental::ICompositionContext &context,
ComponentViewFeatures features)>
m_fnCreateView;
std::function<facebook::react::ComponentDescriptorConstructor *()> m_descriptorConstructorFactory;
winrt::Microsoft::ReactNative::HandleCommandDelegate m_customCommandHandler;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace Microsoft.ReactNative.Composition
void SetViewComponentViewInitializer(ViewComponentViewInitializer initializer);
void SetContentIslandComponentViewInitializer(ComponentIslandComponentViewInitializer initializer);
void SetCreateVisualHandler(CreateVisualDelegate impl);
void SetViewFeatures(ComponentViewFeatures viewFeatures);
};

} // namespace Microsoft.ReactNative
2 changes: 1 addition & 1 deletion vnext/Microsoft.ReactNative/IReactViewComponentBuilder.idl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace Microsoft.ReactNative

[experimental]
DOC_STRING("A delegate that creates a @IComponentProps object for an instance of @ViewProps. See @IReactViewComponentBuilder.SetCreateProps")
delegate IComponentProps ViewPropsFactory(ViewProps props);
delegate IComponentProps ViewPropsFactory(ViewProps props, IComponentProps cloneFrom);

[experimental]
delegate Windows.Foundation.Size MeasureContentHandler(ShadowNode shadowNode, LayoutContext layoutContext, LayoutConstraints layoutConstraints);
Expand Down
2 changes: 2 additions & 0 deletions vnext/Microsoft.ReactNative/ViewProps.idl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ namespace Microsoft.ReactNative {
Microsoft.UI.Composition.CompositionBrush AsBrush(Microsoft.ReactNative.Composition.Theme theme);
#endif

Boolean Equals(Color color);

static Color Black();
static Color Transparent();
static Color ReadValue(IJSValueReader reader);
Expand Down

0 comments on commit 59443c8

Please sign in to comment.