Skip to content

Commit 2cb34bb

Browse files
authored
Switch windows Callout to use codegen for fabric, update native component instructions on Windows (#4197)
* improve agentic authoring on windows * leverage codegen for callout on windows
1 parent 3405262 commit 2cb34bb

50 files changed

Lines changed: 1766 additions & 1533 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/gentle-windows-call.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@fluentui-react-native/callout": patch
3+
---
4+
5+
Use generated Windows Fabric bindings for Callout while preserving the native popup implementation.

.github/skills/agentic-component-authoring/SKILL.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,15 @@ authoring rule in one always-loaded instruction file.
2525

2626
## Load focused references
2727

28-
| Work | Reference |
29-
| ----------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
30-
| Public props, slots, state types, native prop exposure, or exports | [Types and slots](references/types-and-slots.md) |
31-
| Defaults, derived state, interaction hooks, accessibility, or slot construction | [State and accessibility](references/state-and-accessibility.md) |
32-
| Tokens, style factories, theme caching, state precedence, or slot style application | [Styles and tokens](references/styles-and-tokens.md) |
33-
| Pure slot rendering, component assembly, or display names | [Rendering and assembly](references/rendering.md) |
34-
| Runtime tests, type tests, snapshots, Storybook stories, or validation | [Tests and stories](references/tests-and-stories.md) |
35-
| Cross-component duplication, shared helper extraction, or dependency hygiene | [Package optimization](../agentic-component-optimization/SKILL.md) |
28+
| Work | Reference |
29+
| ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
30+
| Public props, slots, state types, native prop exposure, or exports | [Types and slots](references/types-and-slots.md) |
31+
| Defaults, derived state, interaction hooks, accessibility, or slot construction | [State and accessibility](references/state-and-accessibility.md) |
32+
| Tokens, style factories, theme caching, state precedence, or slot style application | [Styles and tokens](references/styles-and-tokens.md) |
33+
| Pure slot rendering, component assembly, or display names | [Rendering and assembly](references/rendering.md) |
34+
| Runtime tests, type tests, snapshots, Storybook stories, or validation | [Tests and stories](references/tests-and-stories.md) |
35+
| Native React Native Windows Fabric components, codegen, registration, or UIA | [Windows Fabric native components](references/windows-fabric-native-components.md) |
36+
| Cross-component duplication, shared helper extraction, or dependency hygiene | [Package optimization](../agentic-component-optimization/SKILL.md) |
3637

3738
A new higher-order component normally needs every reference. A focused fix should load only the affected reference and
3839
its immediate neighbors. Keep the component's colocated `SPEC.md` and companion files authoritative for its contract.

.github/skills/agentic-component-authoring/references/tests-and-stories.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ Each story module should provide:
8787
- focused named stories that compare all values of one axis in one canvas
8888
- `parameters.docs.description.story` for focused scenarios
8989

90+
Stories included in native agent validation also need a stable root `testID`.
91+
Use selectors that describe the component or scenario rather than visible text,
92+
layout order, or native class names. Keep the initial args deterministic and
93+
add identifiers only to the small smoke set that agents and CI actively
94+
validate.
95+
9096
Button uses focused appearance, size, shape, icon, selection, disabled, and constrained-content stories. Icon uses a
9197
source and size overview plus focused font, image, SVG, size, color, and accessibility stories.
9298

@@ -107,6 +113,7 @@ yarn workspace @fluentui-react-native/components lint
107113
yarn workspace @fluentui-react-native/components build
108114
yarn workspace @fluentui-react-native/components test
109115
yarn workspace @fluentui-react-native/agentic-components-storybook bundle:macos
116+
yarn workspace @fluentui-react-native/agentic-components-storybook bundle:windows
110117
```
111118

112119
Run the smallest affected package test while iterating. Run the full package sequence before completion. Run the root
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# Windows Fabric native components
2+
3+
Use this reference when an agentic component needs a native React Native Windows
4+
view. It targets the repository's React Native Windows 0.81 line. Verify APIs
5+
against the installed `react-native-windows` package before adopting guidance
6+
from a newer RNW branch.
7+
8+
## Decide whether native code is required
9+
10+
Prefer a JavaScript component, slots, and React Native primitives when they can
11+
meet the contract. Use a Windows Fabric component when the implementation needs
12+
a Windows-only visual, window, input surface, native API, or performance
13+
boundary that React Native does not expose.
14+
15+
Establish these facts before editing:
16+
17+
- the installed RNW version;
18+
- whether the consuming host uses the New Architecture;
19+
- whether the package must also retain a Paper implementation;
20+
- whether the surface is a view component, TurboModule, or both;
21+
- the canonical Windows, Win32, or macOS behavior to preserve.
22+
23+
RNW Fabric components use C++/WinRT and Windows App SDK Composition visuals.
24+
Do not copy UWP XAML `IViewManager` patterns into the Fabric branch.
25+
26+
## TypeScript native-component specification
27+
28+
Name the schema `<ComponentName>NativeComponent.ts` and keep the component name
29+
identical in TypeScript, generated code, registration, and the JavaScript
30+
wrapper.
31+
32+
```ts
33+
import type { DirectEventHandler, WithDefault } from 'react-native/Libraries/Types/CodegenTypes';
34+
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
35+
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
36+
import type { ViewProps } from 'react-native';
37+
38+
type ValueChangedEvent = {
39+
value: boolean;
40+
};
41+
42+
export interface NativeProps extends ViewProps {
43+
enabled?: WithDefault<boolean, true>;
44+
onValueChanged?: DirectEventHandler<ValueChangedEvent>;
45+
}
46+
47+
export interface NativeCommands {
48+
setValue(viewRef: React.ElementRef<React.ComponentType<NativeProps>>, value: boolean): void;
49+
}
50+
51+
export const Commands = codegenNativeCommands<NativeCommands>({
52+
supportedCommands: ['setValue'],
53+
});
54+
55+
export default codegenNativeComponent<NativeProps>('ExampleNativeView');
56+
```
57+
58+
Use React Native codegen types for native values. Extend `ViewProps` for visual
59+
components. Keep event payloads and commands typed and minimal.
60+
61+
## Windows codegen configuration
62+
63+
Verify the owning package's `codegenConfig`:
64+
65+
```json
66+
{
67+
"codegenConfig": {
68+
"name": "ExampleSpec",
69+
"type": "components",
70+
"jsSrcsDir": "src",
71+
"includesGeneratedCode": true,
72+
"windows": {
73+
"namespace": "ExampleCodegen",
74+
"generators": ["componentsWindows"],
75+
"outputDirectory": "windows/Example/codegen",
76+
"separateDataTypes": true
77+
}
78+
}
79+
}
80+
```
81+
82+
Use `"all"` and include `"modulesWindows"` when the package contains both
83+
TurboModules and components. Run the package's declared codegen command.
84+
Never edit generated props, event-emitter, registration, or `.g.h` files.
85+
Persist corrections in the TypeScript schema or codegen configuration.
86+
87+
## C++/WinRT component view
88+
89+
Third-party Fabric components normally derive from the generated CRTP base:
90+
91+
```cpp
92+
#ifdef RNW_NEW_ARCH
93+
#include "codegen/react/components/ExampleSpec/ExampleNativeView.g.h"
94+
95+
struct ExampleNativeView
96+
: winrt::implements<ExampleNativeView, winrt::IInspectable>,
97+
ExampleCodegen::BaseExampleNativeView<ExampleNativeView> {
98+
winrt::Microsoft::UI::Composition::Visual CreateVisual(
99+
winrt::Microsoft::ReactNative::ComponentView const &view) noexcept override;
100+
101+
void Initialize(
102+
winrt::Microsoft::ReactNative::ComponentView const &view) noexcept override;
103+
104+
private:
105+
winrt::Microsoft::UI::Composition::SpriteVisual m_visual{nullptr};
106+
};
107+
#endif
108+
```
109+
110+
Implement only the hooks the component needs. Generated registration omits
111+
unused optional callbacks.
112+
113+
- Create the root Composition visual in `CreateVisual`.
114+
- Subscribe with `winrt::auto_revoke` and store the revoker.
115+
- Capture `get_weak()` in event and asynchronous callbacks.
116+
- Treat view lifecycle callbacks as UI-thread work.
117+
- Reset reusable native state when the view is recycled.
118+
- Keep native boundary methods `noexcept`, matching RNW patterns.
119+
120+
The generated CRTP base is not the same as subclassing an RNW built-in
121+
`ComponentView`. Do not call a nonexistent `Super` method. When subclassing a
122+
built-in view, preserve its documented base-method ordering.
123+
124+
## Props, events, commands, and state
125+
126+
- Compare old and new props before scheduling visual work.
127+
- Mark affected visuals dirty in prop updates and batch expensive mutation in
128+
the final-update hook.
129+
- Store and null-check the generated event emitter before emitting typed
130+
payloads.
131+
- When a built-in base handles commands, call it first and respect `Handled`.
132+
- Use renderer state only when the renderer must own or measure it. Prefer
133+
props and events for ordinary controlled interaction state.
134+
135+
The RNW `SwitchComponentView` is the canonical source for interactive props,
136+
events, commands, pointer input, keyboard input, focus, and UI Automation.
137+
138+
## Layout and Composition visuals
139+
140+
React layout metrics are in device-independent units while Composition visual
141+
sizes and offsets use physical pixels. Multiply positions and dimensions by
142+
`PointScaleFactor` before assigning them to visuals or geometries.
143+
144+
Mount and unmount child visuals in renderer order. Backgrounds, borders,
145+
shadows, transforms, and clipping are normally supplied through
146+
`ComponentViewFeatures`. Disable a verified feature only when the component
147+
fully replaces it.
148+
149+
Custom clipping may require disabling native border handling and explicitly
150+
updating size and offset from layout metrics. Check the target RNW source
151+
because the feature flags are not exhaustively documented as a public API.
152+
153+
## Theme, input, focus, and accessibility
154+
155+
Native components must support:
156+
157+
- light, dark, and high-contrast updates;
158+
- platform or Fluent brushes instead of fixed native colors where appropriate;
159+
- pointer and keyboard input;
160+
- focus acquisition and focus visuals;
161+
- React Native accessibility props;
162+
- a correct UI Automation control type and patterns;
163+
- UIA property-change notifications for native state changes.
164+
165+
Use Accessibility Insights for Windows or Inspect.exe during initial
166+
development. Add stable `testID` values to the Storybook validation story so
167+
automated checks can locate the component through UIA.
168+
169+
## Registration, projects, and autolinking
170+
171+
The complete persistence chain is:
172+
173+
1. Add hand-authored `.h` and `.cpp` files to the library `.vcxproj`.
174+
2. Add `.vcxproj.filters` entries only for Visual Studio organization.
175+
3. Leave generated code under the codegen build integration.
176+
4. Include the component implementation from `ReactPackageProvider.cpp`.
177+
5. Call the generated `Register<ComponentName>NativeComponent` helper.
178+
6. Preserve attributed TurboModule registration when the package has modules.
179+
7. Regenerate or autolink through the consuming app's declared Windows script.
180+
8. Treat generated autolink files and app solutions as disposable output.
181+
182+
A file on disk but absent from `.vcxproj` is not compiled.
183+
184+
When Fabric and Paper use different component names, generate the Fabric name
185+
directly and set `paperComponentName` in `codegenNativeComponent`. Callout uses
186+
the Fabric name `Callout` and the Paper fallback `RCTCallout`; Windows can
187+
therefore use the generated `RegisterCalloutNativeComponent` helper without
188+
copying or modifying generated registration code.
189+
190+
## Paper compatibility
191+
192+
When a package intentionally supports both architectures, guard Fabric-only
193+
headers and implementation with `RNW_NEW_ARCH` and retain the Paper
194+
`IViewManager` branch separately. Do not share UWP XAML types with WinAppSDK
195+
Composition code.
196+
197+
| Paper | Fabric |
198+
| ----------------------------------------- | ------------------------------------------------------ |
199+
| `IViewManager::CreateView` returning XAML | Generated component base creating a Composition visual |
200+
| Native property map | Codegen props |
201+
| `AddViewManager` | Generated Fabric registration helper |
202+
| XAML child management | Mount and unmount component-view hooks |
203+
| UWP brushes and geometry | Windows App SDK Composition brushes and geometry |
204+
205+
Test architecture branches in separate compatible hosts. For a
206+
New-Architecture-only package, remove obsolete Paper code rather than adding an
207+
untested fallback.
208+
209+
## Validation
210+
211+
Run the smallest declared command at each layer:
212+
213+
1. package format and lint;
214+
2. TypeScript build for the wrapper and schema;
215+
3. Windows codegen check;
216+
4. consuming-app generation or autolink check;
217+
5. clean native package and app build;
218+
6. Storybook Windows bundle;
219+
7. deployed Storybook smoke automation;
220+
8. interaction and native event assertion;
221+
9. UIA assertion;
222+
10. screenshot through the agent host when visual evidence is required;
223+
11. offline Release smoke after packaging or native dependency changes;
224+
12. root build after public type, manifest, or project-reference changes.
225+
226+
A successful JavaScript bundle does not validate native code.
227+
228+
## Canonical sources
229+
230+
- [RNW native platform components](https://microsoft.github.io/react-native-windows/docs/native-platform-components)
231+
- [RNW New Architecture](https://microsoft.github.io/react-native-windows/docs/new-architecture)
232+
- [RNW Windows codegen CLI](https://microsoft.github.io/react-native-windows/docs/codegen-windows-cli)
233+
- [RNW native library autolinking](https://microsoft.github.io/react-native-windows/docs/native-platform-using)
234+
- [RNW NativeModuleSample](https://github.com/microsoft/react-native-windows-samples/tree/main/samples/NativeModuleSample/cpp-lib)
235+
- [RNW built-in Composition views](https://github.com/microsoft/react-native-windows/tree/main/vnext/Microsoft.ReactNative/Fabric/Composition)
236+
237+
Use the installed dependency or matching release branch first. Treat repository
238+
head as discovery material until each API is verified against the pinned RNW
239+
version.

.oxfmtrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"**/*.generated.*",
1111
"**/lib-commonjs/**",
1212
"**/dist/**",
13-
"packages/components/Callout/windows/FRNCallout/codegen/**",
13+
"packages/components/Callout/windows/Callout/codegen/**",
1414
"**/esrp-npm-release-temp/**",
1515
"**/CHANGELOG.*",
1616
"**/CODE_OF_CONDUCT.md",

.yarnrc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,9 @@ packageExtensions:
300300
appium-xcuitest-driver@*:
301301
dependencies:
302302
appium: "*"
303+
devtools@6.12.1:
304+
dependencies:
305+
debug: ^4.4.3
303306
appium@*:
304307
dependencies:
305308
"@colors/colors": "*"

packages/agentic-components/AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ invariants; detailed authoring recipes live in the
1111
- Story files are library source and follow the tests and stories reference.
1212
- Storybook application, native project, Metro, bundle, or CocoaPods work follows `storybook/AGENTS.md` and the
1313
`agentic-storybook-development` skill.
14+
- Native React Native Windows Fabric component work follows the
15+
[Windows Fabric native component reference](../../.github/skills/agentic-component-authoring/references/windows-fabric-native-components.md).
1416

1517
## Package invariants
1618

packages/agentic-components/src/components/button/button.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ const meta: Meta<typeof Button> = {
5252
iconPosition: 'before',
5353
shape: 'rounded',
5454
size: 'medium',
55+
testID: 'agentic-storybook-button',
5556
},
5657
argTypes: {
5758
appearance: { control: 'select', options: appearances.map(({ value }) => value) },

packages/agentic-components/src/primitives/icon/icon.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const meta: Meta<typeof Icon> = {
6565
accessibilityLabel: 'Favorite',
6666
color: '#185abd',
6767
height: 24,
68+
testID: 'agentic-storybook-icon',
6869
width: 24,
6970
},
7071
argTypes: {

packages/agentic-components/storybook/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ windows/*.wrn
3232
windows/ExperimentalFeatures.props
3333
windows/NuGet.Config
3434
dist/
35+
artifacts/

0 commit comments

Comments
 (0)