Fix issue with prop cloning with custom native props (#14061)

* Fix issue with prop cloning with custom native props

* format

* prettier

* Change files

---------

Co-authored-by: React-Native-Windows Bot <53619745+rnbot@users.noreply.github.com>
This commit is contained in:
Andrew Coates 2024-11-02 08:28:21 -07:00 коммит произвёл GitHub
Родитель 9da7ddb7d0
Коммит 59443c8e34
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
18 изменённых файлов: 134 добавлений и 40 удалений

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Fix issue with prop cloning with custom native props",
"packageName": "@react-native-windows/codegen",
"email": "53619745+rnbot@users.noreply.github.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Fix issue with prop cloning with custom native props",
"packageName": "react-native-windows",
"email": "53619745+rnbot@users.noreply.github.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -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);
@ -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,
@ -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]!;
@ -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');

Просмотреть файл

@ -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);
@ -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,

Просмотреть файл

@ -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);
@ -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,

Просмотреть файл

@ -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);
@ -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,

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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()) {

Просмотреть файл

@ -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(

Просмотреть файл

@ -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};

Просмотреть файл

@ -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;

Просмотреть файл

@ -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 {
@ -72,12 +74,15 @@ 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>;
};
@ -85,14 +90,16 @@ void ReactCompositionViewComponentBuilder::SetComponentViewInitializer(
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>;
@ -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);
@ -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;
}

Просмотреть файл

@ -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(
@ -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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);