-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Do not merge: Xaml in RNW prototyping #14649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ | |
|
||
#include "NativeModules.h" | ||
|
||
#include <winrt/Microsoft.ReactNative.Xaml.h> | ||
|
||
// A PackageProvider containing any turbo modules you define within this app project | ||
struct CompReactPackageProvider | ||
: winrt::implements<CompReactPackageProvider, winrt::Microsoft::ReactNative::IReactPackageProvider> { | ||
|
@@ -39,6 +41,10 @@ _Use_decl_annotations_ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE, PSTR | |
RegisterAutolinkedNativeModulePackages(settings.PackageProviders()); | ||
// Register any native modules defined within this app project | ||
settings.PackageProviders().Append(winrt::make<CompReactPackageProvider>()); | ||
// TODO: Can we make apps register this automatically? (e.g. with autolinking) | ||
// TODO: But ideally we don't load the M.RN.Xaml.dll at all if we're not using Xaml. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, that would actually be an interesting thing to try to get autolinking to do. |
||
settings.PackageProviders().Append(winrt::Microsoft::ReactNative::Xaml::ReactPackageProvider()); | ||
|
||
|
||
#if BUNDLE | ||
// Load the JS bundle from a file (not Metro): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,6 +124,12 @@ | |
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Composition.CppApp.targets" Condition="Exists('$(ReactNativeWindowsDir)\PropertySheets\External\Microsoft.ReactNative.Composition.CppApp.targets')" /> | ||
</ImportGroup> | ||
<ItemGroup> | ||
<!-- TODO: Can we make this happen automatically, like with autolinking? --> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, autolinking can do this. But again needs a separate npm package. |
||
<ProjectReference Include="$(ReactNativeWindowsDir)Microsoft.ReactNative.Xaml\Microsoft.ReactNative.Xaml.vcxproj"> | ||
<Project>{e5d1b5d2-0e6a-4011-8bcd-08968256dcbd}</Project> | ||
<Name>Microsoft.ReactNative.Xaml</Name> | ||
<Private Condition="'$(ConfigurationType)' != 'Application'">false</Private> | ||
</ProjectReference> | ||
</ItemGroup> | ||
<Target Name="EnsureReactNativeWindowsTargets" BeforeTargets="PrepareForBuild"> | ||
<PropertyGroup> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
| ||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.13.35913.81 d17.13 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Xaml", "Microsoft.ReactNative.Xaml\Microsoft.ReactNative.Xaml.vcxproj", "{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|ARM64 = Debug|ARM64 | ||
Debug|x64 = Debug|x64 | ||
Debug|x86 = Debug|x86 | ||
Release|ARM64 = Release|ARM64 | ||
Release|x64 = Release|x64 | ||
Release|x86 = Release|x86 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Debug|ARM64.Build.0 = Debug|ARM64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Debug|x64.ActiveCfg = Debug|x64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Debug|x64.Build.0 = Debug|x64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Debug|x86.ActiveCfg = Debug|Win32 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Debug|x86.Build.0 = Debug|Win32 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Release|ARM64.ActiveCfg = Release|ARM64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Release|ARM64.Build.0 = Release|ARM64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Release|x64.ActiveCfg = Release|x64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Release|x64.Build.0 = Release|x64 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Release|x86.ActiveCfg = Release|Win32 | ||
{E5D1B5D2-0E6A-4011-8BCD-08968256DCBD}.Release|x86.Build.0 = Release|Win32 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {3B36CAF0-BCD9-42C7-B311-05FDDCCEC9D4} | ||
EndGlobalSection | ||
EndGlobal |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
namespace Microsoft.ReactNative.Xaml | ||
{ | ||
[webhosthidden][default_interface] runtimeclass XamlApplication : Microsoft.UI.Xaml.Application, | ||
Microsoft.UI.Xaml.Markup.IXamlMetadataProvider | ||
{ | ||
XamlApplication(); | ||
|
||
static void EnsureCreated(); | ||
|
||
static XamlApplication Current { | ||
get; | ||
}; | ||
|
||
void AddMetadataProvider(Microsoft.UI.Xaml.Markup.IXamlMetadataProvider otherProvider); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
#include "pch.h" | ||
|
||
#if !defined(RNW_NEW_ARCH) | ||
static_assert(false, "This module requires RNW_NEW_ARCH to be defined."); | ||
#endif | ||
|
||
#include "FabricXamlControl.h" | ||
|
||
#include <NativeModules.h> | ||
|
||
#include <JSValueComposition.h> | ||
|
||
#include <winrt/Microsoft.ReactNative.Composition.h> | ||
#include <winrt/Microsoft.UI.Composition.h> | ||
|
||
#include <winrt/Microsoft.UI.Xaml.Controls.h> | ||
|
||
namespace winrt::Microsoft::ReactNative::Xaml { | ||
|
||
template <typename TUserData> | ||
void CustomRegisterXamlControlNativeComponent( | ||
winrt::hstring name, | ||
winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder, | ||
std::function<void(const winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder &)> | ||
builderCallback) noexcept { | ||
packageBuilder.as<winrt::Microsoft::ReactNative::IReactPackageBuilderFabric>().AddViewComponent( | ||
name, [name, builderCallback](winrt::Microsoft::ReactNative::IReactViewComponentBuilder const &builder) noexcept { | ||
auto compBuilder = | ||
builder.as<winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder>(); | ||
|
||
builder.SetCreateProps([name]( | ||
winrt::Microsoft::ReactNative::ViewProps props, | ||
const winrt::Microsoft::ReactNative::IComponentProps &cloneFrom) noexcept { | ||
return winrt::make<FabricXamlControlProps>(name, props, cloneFrom); | ||
}); | ||
|
||
builder.SetUpdatePropsHandler([](const winrt::Microsoft::ReactNative::ComponentView &view, | ||
const winrt::Microsoft::ReactNative::IComponentProps &newProps, | ||
const winrt::Microsoft::ReactNative::IComponentProps &oldProps) noexcept { | ||
auto userData = view.UserData().as<TUserData>(); | ||
userData->UpdateProps( | ||
view, | ||
newProps ? newProps.as<FabricXamlControlProps>() : nullptr, | ||
oldProps ? oldProps.as<FabricXamlControlProps>() : 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>(); | ||
userData->UpdateEventEmitter(std::make_shared<FabricXamlControlEventEmitter>(eventEmitter)); | ||
}); | ||
|
||
if constexpr ( | ||
&TUserData::FinalizeUpdate != | ||
&winrt::Microsoft::ReactNative::Xaml::BaseFabricXamlControl<TUserData>::FinalizeUpdate) { | ||
builder.SetFinalizeUpdateHandler([](const winrt::Microsoft::ReactNative::ComponentView &view, | ||
winrt::Microsoft::ReactNative::ComponentViewUpdateMask mask) noexcept { | ||
auto userData = view.UserData().as<TUserData>(); | ||
userData->FinalizeUpdate(view, mask); | ||
}); | ||
} | ||
|
||
if constexpr ( | ||
&TUserData::UpdateState != &winrt::Microsoft::ReactNative::Xaml::BaseFabricXamlControl<TUserData>::UpdateState) { | ||
builder.SetUpdateStateHandler([](const winrt::Microsoft::ReactNative::ComponentView &view, | ||
const winrt::Microsoft::ReactNative::IComponentState &newState) noexcept { | ||
auto userData = view.UserData().as<TUserData>(); | ||
userData->UpdateState(view, newState); | ||
}); | ||
} | ||
|
||
if constexpr ( | ||
&TUserData::MountChildComponentView != | ||
&winrt::Microsoft::ReactNative::Xaml::BaseFabricXamlControl<TUserData>::MountChildComponentView) { | ||
builder.SetMountChildComponentViewHandler( | ||
[](const winrt::Microsoft::ReactNative::ComponentView &view, | ||
const winrt::Microsoft::ReactNative::MountChildComponentViewArgs &args) noexcept { | ||
auto userData = view.UserData().as<TUserData>(); | ||
return userData->MountChildComponentView(view, args); | ||
}); | ||
} | ||
|
||
if constexpr ( | ||
&TUserData::UnmountChildComponentView != | ||
&winrt::Microsoft::ReactNative::Xaml::BaseFabricXamlControl<TUserData>::UnmountChildComponentView) { | ||
builder.SetUnmountChildComponentViewHandler( | ||
[](const winrt::Microsoft::ReactNative::ComponentView &view, | ||
const winrt::Microsoft::ReactNative::UnmountChildComponentViewArgs &args) noexcept { | ||
auto userData = view.UserData().as<TUserData>(); | ||
return userData->UnmountChildComponentView(view, args); | ||
}); | ||
} | ||
|
||
compBuilder.SetViewComponentViewInitializer( | ||
[name](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept { | ||
auto userData = winrt::make_self<TUserData>(name); | ||
if constexpr ( | ||
&TUserData::Initialize != | ||
&winrt::Microsoft::ReactNative::Xaml::BaseFabricXamlControl<TUserData>::Initialize) { | ||
userData->Initialize(view); | ||
} | ||
view.UserData(*userData); | ||
}); | ||
|
||
if constexpr ( | ||
&TUserData::CreateVisual != &winrt::Microsoft::ReactNative::Xaml::BaseFabricXamlControl<TUserData>::CreateVisual) { | ||
compBuilder.SetCreateVisualHandler([](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept { | ||
// I suppose we should return null here since we're not backed by a visual? | ||
// No, it looks like in CompositionViewComponentView.cpp ViewComponentView::ensureVisual that this will | ||
// fail. | ||
// TODO: Don't create a dummy visual here. | ||
auto userData = view.UserData().as<TUserData>(); | ||
return userData->CreateVisual(view); | ||
}); | ||
} | ||
|
||
// Allow app to further customize the builder | ||
if (builderCallback) { | ||
builderCallback(compBuilder); | ||
} | ||
}); | ||
} | ||
|
||
} // namespace winrt::Microsoft::ReactNative::Xaml | ||
|
||
void RegisterXamlControl(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) { | ||
winrt::Microsoft::ReactNative::Xaml::CustomRegisterXamlControlNativeComponent< | ||
winrt::Microsoft::ReactNative::Xaml::XamlControlComponentView>( | ||
winrt::hstring{L"FX_StackPanel"}, | ||
packageBuilder, | ||
[](const winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder &builder) { | ||
UNREFERENCED_PARAMETER(builder); | ||
// TODO: Do we need to do anything here? | ||
}); | ||
|
||
winrt::Microsoft::ReactNative::Xaml::CustomRegisterXamlControlNativeComponent< | ||
winrt::Microsoft::ReactNative::Xaml::XamlControlComponentView>( | ||
winrt::hstring{L"FX_Button"}, | ||
packageBuilder, | ||
[](const winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder &builder) { | ||
UNREFERENCED_PARAMETER(builder); | ||
// TODO: Do we need to do anything here? | ||
}); | ||
|
||
winrt::Microsoft::ReactNative::Xaml::CustomRegisterXamlControlNativeComponent< | ||
winrt::Microsoft::ReactNative::Xaml::XamlControlComponentView>( | ||
winrt::hstring{L"FX_CalendarView"}, | ||
packageBuilder, | ||
[](const winrt::Microsoft::ReactNative::Composition::IReactCompositionViewComponentBuilder &builder) { | ||
UNREFERENCED_PARAMETER(builder); | ||
// TODO: Do we need to do anything here? | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get autolinking to do its thing, we'd need to move the rn-xaml JS code into a new npm package, and then autolinking would bring in this dependency if the app adds that new package to their dependencies.