-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Xaml support prototype #14811
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?
Xaml support prototype #14811
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 |
---|---|---|
@@ -0,0 +1,14 @@ | ||
setlocal | ||
pushd ..\.. | ||
|
||
call yarn || goto :fail | ||
|
||
popd | ||
|
||
call yarn react-native run-windows --msbuildprops RestoreForceEvaluate=true || goto :fail | ||
|
||
echo Success! | ||
exit /b 0 | ||
|
||
echo FAILED. | ||
exit /b 1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,6 +83,17 @@ | |
"boost": "[1.83.0, )" | ||
} | ||
}, | ||
"microsoft.reactnative.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. I'm not sure why this entry is here -- "microsoft.reactnative.xaml" isn't a package, is it? 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. lock files include project dependencies 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. OK, this should go away when we remove the m.rn.xaml.vcxproj then. |
||
"type": "Project", | ||
"dependencies": { | ||
"Common": "[1.0.0, )", | ||
"Folly": "[1.0.0, )", | ||
"Microsoft.ReactNative": "[1.0.0, )", | ||
"Microsoft.WindowsAppSDK": "[1.7.250401001, )", | ||
"ReactCommon": "[1.0.0, )", | ||
"boost": "[1.83.0, )" | ||
} | ||
}, | ||
"reactcommon": { | ||
"type": "Project", | ||
"dependencies": { | ||
|
@@ -95,6 +106,18 @@ | |
"dependencies": { | ||
"Microsoft.JavaScript.Hermes": "[0.0.0-2505.2001-0e4bc3b9, )", | ||
"Microsoft.ReactNative": "[1.0.0, )", | ||
"Microsoft.ReactNative.Xaml": "[1.0.0, )", | ||
"Microsoft.VCRTForwarders.140": "[1.0.2-rc, )", | ||
"Microsoft.WindowsAppSDK": "[1.7.250401001, )", | ||
"XamlCalendarView": "[1.0.0, )", | ||
"boost": "[1.83.0, )" | ||
} | ||
}, | ||
"xamlcalendarview": { | ||
"type": "Project", | ||
"dependencies": { | ||
"Microsoft.ReactNative": "[1.0.0, )", | ||
"Microsoft.ReactNative.Xaml": "[1.0.0, )", | ||
"Microsoft.VCRTForwarders.140": "[1.0.2-rc, )", | ||
"Microsoft.WindowsAppSDK": "[1.7.250401001, )", | ||
"boost": "[1.83.0, )" | ||
|
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,9 @@ _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. | ||
settings.PackageProviders().Append(winrt::Microsoft::ReactNative::Xaml::ReactPackageProvider()); | ||
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. TODO: I don't know how to make this automatically happen with autolinking or whatever. Can the xaml-calendar-view package do this somehow? OTOH, if the app's not using Xaml, I don't want it to load Microsoft.ReactNative.Xaml.dll. Not sure the best way to handle this. 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. We would probably want to update autolinking to conditionally add the We can either detect it needs to be there during autolinking (modules might register that they need it) and inject it there, OR we could just always put it in, behind a 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. Another solution: if XamlHost were in its own package, the existing autolinking logic should make this work. 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. DECISION: We decided to remove the Microsoft.ReactNative.Xaml.dll and move XamlHost into Microsoft.ReactNative.dll. This should resolve this problem. |
||
|
||
#if BUNDLE | ||
// Load the JS bundle from a file (not Metro): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
lib-commonjs/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<configuration> | ||
<packageSources> | ||
<clear /> | ||
<add key="react-native" value="https://pkgs.dev.azure.com/ms/react-native/_packaging/react-native-public/nuget/v3/index.json" /> | ||
<add key="Nuget.org" value="https://api.nuget.org/v3/index.json" /> | ||
</packageSources> | ||
<disabledPackageSources> | ||
<clear /> | ||
</disabledPackageSources> | ||
</configuration> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = { | ||
presets: ['module:@rnw-scripts/babel-react-native-config'], | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = { | ||
preset: 'react-native', | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** | ||
* Copyright (c) Microsoft Corporation. | ||
* Licensed under the MIT License. | ||
* @format | ||
* @ts-check | ||
*/ | ||
|
||
const {task, series} = require('just-scripts'); | ||
const fs = require('fs'); | ||
const glob = require('glob'); | ||
const path = require('path'); | ||
|
||
// Use the shared base configuration | ||
require('@rnw-scripts/just-task'); | ||
|
||
// The TS build process will strip all the types from the NativeComponent spec file. Which means that the codegen babel will not correctly generate the JS view config for the component. | ||
// So here we manually run babel, overwriting the tsc output, so that we ship the generated code. | ||
task('codegenNativeComponents', () => { | ||
const babel = require('@babel/core'); | ||
const matches = glob.sync('src/**/*NativeComponent.ts'); | ||
|
||
matches.forEach(matchedPath => { | ||
const relativePath = path.relative( | ||
path.resolve(process.cwd(), 'src'), | ||
matchedPath, | ||
); | ||
const code = fs.readFileSync(matchedPath).toString(); | ||
const filename = path.resolve(process.cwd(), matchedPath); | ||
|
||
const res = babel.transformSync(code, { | ||
ast: false, | ||
filename, | ||
cwd: process.cwd(), | ||
sourceRoot: process.cwd(), | ||
root: process.cwd(), | ||
babelrc: true, | ||
}); | ||
|
||
const relativeOutputPath = relativePath.replace(/\.ts$/, '.js'); | ||
|
||
fs.writeFileSync( | ||
path.resolve(process.cwd(), 'lib-commonjs', relativeOutputPath), | ||
res?.code, | ||
); | ||
}); | ||
}); | ||
|
||
task( | ||
'buildWithCodegetNativeComponents', | ||
series('build', 'codegenNativeComponents'), | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
{ | ||
"name": "xaml-calendar-view", | ||
"version": "1.0.0", | ||
"main": "lib-commonjs/index.js", | ||
"types": "lib-commonjs/index.d.ts", | ||
"license": "MIT", | ||
"private": true, | ||
"scripts": { | ||
"build": "rnw-scripts buildWithCodegetNativeComponents", | ||
"lint": "rnw-scripts lint", | ||
"lint:fix": "rnw-scripts lint:fix" | ||
}, | ||
"codegenConfig": { | ||
"name": "CalendarView", | ||
"type": "all", | ||
"jsSrcsDir": "src", | ||
"windows": { | ||
"generators": "componentsWindows", | ||
"namespace": "winrt::XamlCalendarView::Codegen", | ||
"outputDirectory": "windows/XamlCalendarView/codegen" | ||
} | ||
}, | ||
"dependencies": { | ||
"@types/react": "^19.0.0", | ||
"react": "^19.0.0", | ||
"react-native": "0.79.0-nightly-20250123-d1028885e", | ||
"react-native-windows": "^0.0.0-canary.952" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.25.2", | ||
"@babel/generator": "^7.25.0", | ||
"@babel/preset-env": "^7.25.3", | ||
"@babel/preset-typescript": "^7.8.3", | ||
"@babel/runtime": "^7.20.0", | ||
"@react-native-community/cli": "15.0.0-alpha.2", | ||
"@react-native/metro-config": "0.79.0-nightly-20250123-d1028885e", | ||
"@rnw-scripts/babel-node-config": "2.3.2", | ||
"@rnw-scripts/babel-react-native-config": "0.0.0", | ||
"@rnw-scripts/eslint-config": "1.2.34", | ||
"@rnw-scripts/just-task": "2.3.51", | ||
"@rnw-scripts/metro-dev-config": "0.0.0", | ||
"@rnw-scripts/ts-config": "2.0.5", | ||
"@rnx-kit/jest-preset": "^0.1.16", | ||
"@types/react": "^19.0.0", | ||
"@typescript-eslint/eslint-plugin": "^7.1.1", | ||
"@typescript-eslint/parser": "^7.1.1", | ||
"babel-jest": "^29.6.3", | ||
"eslint": "^8.19.0", | ||
"glob": "^7.1.6", | ||
"just-scripts": "^1.3.3", | ||
"prettier": "2.8.8", | ||
"typescript": "5.0.4" | ||
}, | ||
"engines": { | ||
"node": ">=18" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
|
||
import * as React from 'react'; | ||
import RawCalendarView from './CalendarViewNativeComponent'; | ||
|
||
import XamlHost from 'react-native-windows/Libraries/Components/Xaml/XamlHost'; | ||
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. This is an awkward import into a deep path. Should XamlHost be a separate package? |
||
|
||
function CalendarView(props: any) { | ||
return ( | ||
<XamlHost label='unused'> | ||
<RawCalendarView label='unused' {...props} /> | ||
</XamlHost> | ||
); | ||
} | ||
|
||
export { CalendarView, RawCalendarView }; | ||
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. The idea here is that the CalendarView object is already wrapped in a XamlHost, so is all ready to be put into a JSX tree. RawCalendarView is not. In the future maybe we make it possible to group multiple "Raw" elements under the same XamlHost. 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. If you had a tree of Xaml elements, would you expect something like this? (maybe not supporting layout panels with multiple children, but other controls that have 1 child)
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. I think we could support this without too much work if we want to. I haven't spent a lot of time exploring that though. |
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.
This version should be more concrete.