From a28b2d7752ea86239f0427ebf0879f8663c14910 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 2 Oct 2026 12:10:02 -0700 Subject: [PATCH 1/5] initial package framing for native-core --- .changeset/modern-native-core.md | 5 + AGENTS.md | 9 +- packages/agentic/native-core/README.md | 205 ++++++++++++++++++ packages/agentic/native-core/package.json | 73 +++++++ packages/agentic/native-core/src/index.ts | 1 + .../agentic/native-core/src/macos/index.ts | 1 + packages/agentic/native-core/src/win/index.ts | 1 + .../agentic/native-core/src/win32/index.ts | 1 + .../agentic/native-core/src/windows/index.ts | 1 + .../native-core/tests/entrypoints.test.mjs | 57 +++++ packages/agentic/native-core/tsconfig.json | 16 ++ tsconfig.json | 3 + yarn.lock | 8 + 13 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 .changeset/modern-native-core.md create mode 100644 packages/agentic/native-core/README.md create mode 100644 packages/agentic/native-core/package.json create mode 100644 packages/agentic/native-core/src/index.ts create mode 100644 packages/agentic/native-core/src/macos/index.ts create mode 100644 packages/agentic/native-core/src/win/index.ts create mode 100644 packages/agentic/native-core/src/win32/index.ts create mode 100644 packages/agentic/native-core/src/windows/index.ts create mode 100644 packages/agentic/native-core/tests/entrypoints.test.mjs create mode 100644 packages/agentic/native-core/tsconfig.json diff --git a/.changeset/modern-native-core.md b/.changeset/modern-native-core.md new file mode 100644 index 0000000000..918f484f9b --- /dev/null +++ b/.changeset/modern-native-core.md @@ -0,0 +1,5 @@ +--- +"@fluentui-react-native/native-core": minor +--- + +Initialize the native-core package with cross-platform, macOS, Windows, shared Windows/Win32, and Win32 entrypoints and a native component and TurboModule organization plan. diff --git a/AGENTS.md b/AGENTS.md index 7d8f922586..b2d3381a1c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -86,6 +86,7 @@ This is the **FluentUI React Native** repository, a monorepo containing React Na /win32/ - Win32-specific test app /component-generator/ - Tool to generate new components /packages/ - Core library packages + /agentic/native-core/ - Shared modern native components and TurboModules /components/ - UI component implementations (Button, Checkbox, Avatar, etc.) /native/ - Standalone native-backed component packages (Callout, etc.) /framework/ - Core theming and composition framework @@ -238,7 +239,8 @@ The composition framework uses precise types for better type safety: ### Component Development **Component Location**: Stable JavaScript components are in `/packages/components/`, standalone native-backed components are in -`/packages/native/`, and components under development are in `/packages/experimental/`. +`/packages/native/`, and components under development are in `/packages/experimental/`. New modern native components and +modules share `/packages/agentic/native-core/`; follow its [organization plan](packages/agentic/native-core/README.md). **Component Structure**: Each component typically has: @@ -281,6 +283,11 @@ native code (iOS/Android/Windows): - iOS/macOS: Include `.podspec` files - Must be added to FluentTester's Podfile (transitive dependencies aren't autolinked) +For new modern native components and modules, use `@fluentui-react-native/native-core` rather than creating another standalone +package. Its Windows components are Fabric-only; macOS components support Paper and Fabric initially. Export shared APIs +from the root and scope platform APIs to `macos`, `windows` (React Native Windows), `win` (Windows/Win32), or `win32`. +Existing native packages are not migrated by this convention. + ### Creating a New Component 1. Create the package under `/packages/components/`, `/packages/native/` for a standalone diff --git a/packages/agentic/native-core/README.md b/packages/agentic/native-core/README.md new file mode 100644 index 0000000000..5816756caf --- /dev/null +++ b/packages/agentic/native-core/README.md @@ -0,0 +1,205 @@ +# Native Core + +`@fluentui-react-native/native-core` is the shared home for new native-backed +components and non-UI native modules. JavaScript should generally be a thin, +typed wrapper around native behavior, not a second implementation of it. +Higher-order Fluent components, theming, and composition remain in their +existing packages and can consume this package without introducing a reverse +dependency. + +## Initialization status + +The workspace, TypeScript build, package export map, and entrypoint contract +tests are initialized. All five entrypoints are intentionally empty. There are +no native implementations, codegen specs, native projects, or autolinking +registrations yet. This does not migrate Callout, FocusZone, or any other +existing package. + +The initial shell has no runtime dependencies. Add React Native/React peers, +optional platform-fork peers, development dependencies, and matching `rnx-kit` +capabilities with the first implementation, using the repository's supported +versions. Do not imply native compatibility from an empty entrypoint. + +## Public entrypoints + +| Import | Scope | Source entrypoint | +| -------------------------------------------- | --------------------------------------- | ---------------------- | +| `@fluentui-react-native/native-core` | Cross-platform APIs | `src/index.ts` | +| `@fluentui-react-native/native-core/macos` | macOS-specific APIs | `src/macos/index.ts` | +| `@fluentui-react-native/native-core/windows` | React Native Windows-specific APIs | `src/windows/index.ts` | +| `@fluentui-react-native/native-core/win` | APIs shared by Windows and Win32 | `src/win/index.ts` | +| `@fluentui-react-native/native-core/win32` | Office React Native Win32-specific APIs | `src/win32/index.ts` | + +Each entrypoint explicitly exports components, module facades, and their +public types. The root is not an umbrella export of the platform submodules; +`win` is not an umbrella export of `windows` and `win32`. Give an API its +narrowest applicable public home. Shared implementation does not itself make +an API cross-platform. + +Root exports require equivalent implementations on all supported desktop +hosts: macOS, React Native Windows, and Win32. Additional platform support +must be stated and verified per API; this initialization does not promise +iOS or Android support. A `win` export must work on both Windows hosts, +despite their potentially different native implementations. + +Keep platform imports behind the corresponding entrypoint and implementation +file. Importing one entrypoint must not initialize another platform's native +components or module registry. Keep schemas, generated bindings, registration, +and internal helpers private; the export map deliberately disallows deep +imports. Never use wildcard re-exports. + +## JavaScript and specification layout + +Only the entrypoint files exist initially. Add the following directories as +real features arrive rather than filling them with placeholder native APIs: + +```text +src/ + index.ts + macos/index.ts + windows/index.ts + win/index.ts + win32/index.ts + components/ + / + .tsx Thin public wrapper, when shared + .types.ts Public props, events, commands, and refs + ..tsx Platform binding when needed + .test.tsx Wrapper behavior tests + .types.test.ts Public type contract + SPEC.md Supported platforms and renderer behavior + modules/ + / + .ts Typed public facade over a native module + ..ts Platform binding when needed + .test.ts Facade and error propagation tests + SPEC.md Availability, threading, events, and lifetime + specs/ + components/ + NativeComponent.ts Fabric props, events, and native commands + modules/ + Native.ts TurboModule interface + internal/ Private shared boundary utilities, as needed +``` + +Use React Native codegen-compatible schemas as the JS/native source of truth. +Keep public ergonomic props separate from the lower-level native schema only +when translation is necessary. Native component wrappers forward props, +events, commands, children, and native refs; module facades normalize only +the behavior needed for the public contract. + +Use `.macos`, `.windows`, and `.win32` implementation files for real host +differences. `win` is a package scope, not a Metro platform extension. Keep +React Native fork imports out of the shared TypeScript type graph; use +platform-specific files or platform-neutral shapes. Missing required native +registrations must surface a descriptive error, not a no-op component or a +success-shaped module fallback. + +## Native layout and architecture + +The planned native layout separates UI components from non-UI modules and +shares platform behavior below the renderer adapters: + +```text +macos/ + components// + shared/ AppKit view and behavior + fabric/ Fabric component-view adapter + paper/ Temporary Paper view-manager adapter + modules// TurboModule implementation and required glue + shared/ Platform utilities used by multiple features + registration/ Component and module provider wiring +windows/ + NativeCore/ + components// Fabric component views + modules// TurboModule implementations + shared/ C++/WinRT platform utilities + registration/ ReactPackageProvider wiring + codegen/ Generated Windows bindings, never hand-edited +win32/ Host-specific integration, only when needed +FRNNativeCore.podspec macOS sources and native dependencies +react-native.config.cjs Native project discovery/autolinking +``` + +| Host | Native component policy | Non-UI module policy | +| -------------------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | +| React Native Windows (`windows`) | Fabric only; no new Paper view managers or fallback path | TurboModules, with host support verified per module | +| macOS (`macos`) | Both Paper and Fabric initially; Fabric-only long term | TurboModules; add narrowly scoped legacy-host glue only when required and verified | +| Office Win32 (`win32`) | Explicit host contract per feature; do not assume the RNW Fabric implementation is compatible | Explicit host registration and module availability per feature | + +On macOS, Paper and Fabric adapters must expose the same props, events, +commands, refs, and behavior while delegating to shared AppKit logic. +Keep Paper-specific code in `paper/` and guard native compilation with the +host's architecture configuration. Retire that adapter after supported macOS +hosts become Fabric-only, without changing the public JS API. + +The Windows component project must require the New Architecture and fail +clearly for a Paper build. Use the repository's +[Windows Fabric native component reference](../../../.github/skills/agentic-component-authoring/references/windows-fabric-native-components.md) +and verify APIs against the installed RNW version. +Win32 integration is separate from React Native Windows Paper support; adding +a Win32 export does not authorize a second RNW view-manager implementation. + +Component renderer support and TurboModule availability are separate +capabilities. Do not infer module availability solely from Fabric being +enabled. Modules own their native threading, resource cleanup, event +subscriptions, and cancellation contracts; wrappers preserve those contracts +and expose native failures. + +## Codegen, registration, and publishing plan + +Introduce native build metadata with the first real schema and native target: + +1. Use one package-level codegen identity, `FRNNativeCoreSpec`, with + `type: "all"` and `jsSrcsDir: "src/specs"` so components and modules remain + distinct in source but share a generation boundary. +2. Name component schemas `NativeComponent.ts` and module schemas + `Native.ts`. Prefix native registration names with `FRNNativeCore` + to avoid collisions with existing packages; keep each name identical in + the schema, generated interface, native registration, and JS binding. +3. Configure Windows with both `componentsWindows` and `modulesWindows` + generators and `windows/NativeCore/codegen` output. Apple codegen should + run through the consuming macOS app's Pod integration. Inspect each + platform's generated schema and provider list so platform-only APIs do + not require registration on unrelated hosts. +4. Leave `includesGeneratedCode` unset unless generated artifacts for every + supported native platform are deliberately shipped and verified. It is + not a Windows-only switch and can prevent Apple code generation. +5. Add the macOS podspec, Windows project/provider, and autolinking metadata + only when they refer to real sources. Exclude Paper adapters from macOS + Fabric compilation and Fabric adapters from Paper compilation. Register + only implementations supported by the active host/architecture. +6. Keep native targets and required generated outputs in the published + archive. The initial `files` allowlist reserves `src`, `lib`, `macos`, + `windows`, `win32`, podspecs, and `react-native.config.cjs`. Intermediate + native build artifacts, tests, and machine-local project output must not + leak into it. +7. Verify the packed package in consuming hosts before replacing an existing + package. Migrations are separate changes with compatibility evidence, not + implicit effects of adding this workspace. + +## Delivery and validation + +Add each feature as one reviewed contract, thin wrapper/schema, native +implementation, explicit export, and tests. Start with one representative +Fabric component and one TurboModule to exercise both codegen paths. +macOS component admission requires both Paper and Fabric evidence; Windows +component admission requires Fabric evidence. A `win` or root API also +requires Win32 evidence before it is exported there. + +Run the owning workspace's scripts from the repository root: + +```sh +yarn workspace @fluentui-react-native/native-core format --check +yarn workspace @fluentui-react-native/native-core lint +yarn workspace @fluentui-react-native/native-core build +yarn workspace @fluentui-react-native/native-core test +yarn build +``` + +The initial Node tests validate all five export maps, emitted JS/declaration +files, and conditional resolution for compiled, React Native source, and +TypeScript entrypoints. Add the repository's shared Jest configuration and +native integration tests when wrappers and native targets exist. Native +verification must cover registration, events/commands, refs, unmount cleanup, +error propagation, and architecture/platform parity, not only JS mocks. diff --git a/packages/agentic/native-core/package.json b/packages/agentic/native-core/package.json new file mode 100644 index 0000000000..6542e731eb --- /dev/null +++ b/packages/agentic/native-core/package.json @@ -0,0 +1,73 @@ +{ + "name": "@fluentui-react-native/native-core", + "version": "0.0.1", + "description": "Modern native components and modules for Fluent UI React Native.", + "license": "MIT", + "author": "", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/fluentui-react-native.git", + "directory": "packages/agentic/native-core" + }, + "files": [ + "lib", + "src", + "macos", + "windows", + "win32", + "*.podspec", + "react-native.config.cjs" + ], + "type": "module", + "sideEffects": false, + "main": "lib/index.js", + "module": "lib/index.js", + "types": "lib/index.d.ts", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "react-native": "./src/index.ts", + "import": "./lib/index.js", + "default": "./src/index.ts" + }, + "./macos": { + "types": "./lib/macos/index.d.ts", + "react-native": "./src/macos/index.ts", + "import": "./lib/macos/index.js", + "default": "./src/macos/index.ts" + }, + "./windows": { + "types": "./lib/windows/index.d.ts", + "react-native": "./src/windows/index.ts", + "import": "./lib/windows/index.js", + "default": "./src/windows/index.ts" + }, + "./win": { + "types": "./lib/win/index.d.ts", + "react-native": "./src/win/index.ts", + "import": "./lib/win/index.js", + "default": "./src/win/index.ts" + }, + "./win32": { + "types": "./lib/win32/index.d.ts", + "react-native": "./src/win32/index.ts", + "import": "./lib/win32/index.js", + "default": "./src/win32/index.ts" + }, + "./package.json": "./package.json" + }, + "scripts": { + "build": "tsc -b", + "clean": "fluentui-scripts clean", + "format": "fluentui-scripts format", + "lint": "fluentui-scripts lint", + "test": "yarn build && node --test tests/entrypoints.test.mjs" + }, + "devDependencies": { + "@fluentui-react-native/scripts": "workspace:*" + }, + "rnx-kit": { + "kitType": "library", + "extends": "@fluentui-react-native/scripts/kit-config" + } +} diff --git a/packages/agentic/native-core/src/index.ts b/packages/agentic/native-core/src/index.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/agentic/native-core/src/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/agentic/native-core/src/macos/index.ts b/packages/agentic/native-core/src/macos/index.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/agentic/native-core/src/macos/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/agentic/native-core/src/win/index.ts b/packages/agentic/native-core/src/win/index.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/agentic/native-core/src/win/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/agentic/native-core/src/win32/index.ts b/packages/agentic/native-core/src/win32/index.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/agentic/native-core/src/win32/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/agentic/native-core/src/windows/index.ts b/packages/agentic/native-core/src/windows/index.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/agentic/native-core/src/windows/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/agentic/native-core/tests/entrypoints.test.mjs b/packages/agentic/native-core/tests/entrypoints.test.mjs new file mode 100644 index 0000000000..3fda319b2f --- /dev/null +++ b/packages/agentic/native-core/tests/entrypoints.test.mjs @@ -0,0 +1,57 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { access, readFile } from 'node:fs/promises'; +import test from 'node:test'; +import { fileURLToPath } from 'node:url'; + +const packageRoot = new URL('../', import.meta.url); +const manifest = JSON.parse(await readFile(new URL('package.json', packageRoot), 'utf8')); +const entrypoints = [ + ['.', 'index'], + ['./macos', 'macos/index'], + ['./windows', 'windows/index'], + ['./win', 'win/index'], + ['./win32', 'win32/index'], +]; + +test('declares exactly the five public entrypoints and package metadata', () => { + assert.equal(manifest.name, '@fluentui-react-native/native-core'); + assert.deepEqual(Object.keys(manifest.exports), [...entrypoints.map(([entrypoint]) => entrypoint), './package.json']); + assert.equal(manifest.exports['./package.json'], './package.json'); + assert.equal(manifest.main, 'lib/index.js'); + assert.equal(manifest.module, 'lib/index.js'); + assert.equal(manifest.types, 'lib/index.d.ts'); +}); + +for (const [entrypoint, path] of entrypoints) { + test(`${entrypoint} has distinct source, JavaScript, and declaration targets`, async () => { + const expected = { + types: `./lib/${path}.d.ts`, + 'react-native': `./src/${path}.ts`, + import: `./lib/${path}.js`, + default: `./src/${path}.ts`, + }; + assert.deepEqual(manifest.exports[entrypoint], expected); + assert.deepEqual(Object.keys(manifest.exports[entrypoint]), Object.keys(expected)); + await Promise.all(Object.values(expected).map((target) => access(new URL(target, packageRoot)))); + }); +} + +for (const condition of ['import', 'react-native', 'types']) { + test(`${condition} resolution selects the correct public entrypoints`, () => { + const specifiers = entrypoints.map(([entrypoint]) => manifest.name + (entrypoint === '.' ? '' : entrypoint.slice(1))); + const script = `console.log(JSON.stringify(${JSON.stringify(specifiers)}.map((specifier) => import.meta.resolve(specifier))))`; + const args = condition === 'import' ? [] : [`--conditions=${condition}`]; + const result = spawnSync(process.execPath, [...args, '--input-type=module', '--eval', script], { + cwd: fileURLToPath(packageRoot), + encoding: 'utf8', + }); + + assert.ifError(result.error); + assert.equal(result.status, 0, result.stderr); + assert.deepEqual( + JSON.parse(result.stdout), + entrypoints.map(([entrypoint]) => new URL(manifest.exports[entrypoint][condition], packageRoot).href), + ); + }); +} diff --git a/packages/agentic/native-core/tsconfig.json b/packages/agentic/native-core/tsconfig.json new file mode 100644 index 0000000000..d952200ef0 --- /dev/null +++ b/packages/agentic/native-core/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@fluentui-react-native/scripts/tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + "composite": true, + "tsBuildInfoFile": ".cache/tsconfig.tsbuildinfo" + }, + "include": ["src"], + "exclude": ["**/*.stories.ts", "**/*.stories.tsx", "**/*.wdio.ts"], + "references": [ + { + "path": "../../../scripts/tsconfig.json" + } + ] +} diff --git a/tsconfig.json b/tsconfig.json index d2f500b851..2d951847c5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,6 +28,9 @@ { "path": "packages/agentic/desktop-driver/tsconfig.json" }, + { + "path": "packages/agentic/native-core/tsconfig.json" + }, { "path": "packages/agentic/storybook-desktop/tsconfig.json" }, diff --git a/yarn.lock b/yarn.lock index 3fa2fa59ba..9357564ab9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4515,6 +4515,14 @@ __metadata: languageName: unknown linkType: soft +"@fluentui-react-native/native-core@workspace:packages/agentic/native-core": + version: 0.0.0-use.local + resolution: "@fluentui-react-native/native-core@workspace:packages/agentic/native-core" + dependencies: + "@fluentui-react-native/scripts": "workspace:*" + languageName: unknown + linkType: soft + "@fluentui-react-native/notification@workspace:*, @fluentui-react-native/notification@workspace:packages/components/Notification": version: 0.0.0-use.local resolution: "@fluentui-react-native/notification@workspace:packages/components/Notification" From 4c184851504478567bf5f5221a0b72fec5617170 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 2 Oct 2026 13:06:16 -0700 Subject: [PATCH 2/5] move callout and focus-zone into native-core package --- .changeset/modern-native-core.md | 2 + .changeset/native-core-component-migration.md | 9 ++ .../references/focus-macos.md | 16 +- .../references/focus-windows.md | 4 +- .gitignore | 6 + .oxfmtrc.json | 2 +- AGENTS.md | 20 +-- apps/E2E/tsconfig.json | 2 +- apps/fluent-tester/package.json | 1 + apps/fluent-tester/tsconfig.json | 7 +- apps/storybook/README.md | 14 +- apps/storybook/agent-map.yaml | 2 +- apps/storybook/package.json | 6 +- apps/storybook/storybook.config.mts | 2 +- apps/storybook/tsconfig.json | 11 +- apps/tester-core/tsconfig.json | 4 +- .../agentic/components/WIN32-FOCUS-PLAN.md | 18 +-- packages/agentic/components/package.json | 7 +- .../focus-zone/focus-zone.stories.tsx | 4 +- packages/agentic/components/tsconfig.json | 11 +- .../native-core/FRNNativeCore.podspec} | 6 +- .../native-core}/NuGet.config | 0 packages/agentic/native-core/README.md | 70 ++++---- .../native-core}/jest.config.cjs | 0 .../Callout/fabric}/RCTCalloutComponentView.h | 0 .../fabric}/RCTCalloutComponentView.mm | 10 +- .../Callout/paper}/CalloutManager.swift | 0 .../Callout/paper}/FRNCalloutManager.h | 0 .../Callout/paper}/FRNCalloutManager.m | 2 +- .../Callout/shared}/CalloutView.swift | 0 .../Callout/shared}/CalloutWindow.swift | 0 .../components/Callout/shared}/FRNCallout.h | 2 +- .../shared}/FlippedVisualEffectView.swift | 0 .../Callout/shared}/GuardedEventMonitor.swift | 0 .../fabric}/RCTFocusZoneComponentView.h | 0 .../fabric}/RCTFocusZoneComponentView.mm | 10 +- .../FocusZone/paper}/RCTFocusZoneManager.h | 0 .../FocusZone/paper}/RCTFocusZoneManager.m | 2 +- .../components/FocusZone/shared}/KeyCodes.h | 0 .../FocusZone/shared}/RCTFocusZone.h | 0 .../FocusZone/shared}/RCTFocusZone.m | 0 packages/agentic/native-core/package.json | 107 +++++++++++- .../native-core}/react-native.config.cjs | 2 +- .../components/callout}/Callout.stories.tsx | 0 .../src/components/callout}/Callout.tsx | 2 +- .../src/components/callout}/Callout.types.ts | 0 .../src/components/callout}/SPEC.md | 12 +- .../callout}/__tests__/Callout.test.tsx | 2 +- .../callout}/__tests__/Callout.types.test.ts | 0 .../__snapshots__/Callout.test.tsx.snap | 0 .../src/components/focus-zone}/FocusZone.tsx | 2 +- .../components/focus-zone}/FocusZone.types.ts | 0 .../src/components/focus-zone}/SPEC.md | 11 +- .../focus-zone}/__tests__/FocusZone.test.tsx | 0 .../__tests__/FocusZone.types.test.ts | 0 packages/agentic/native-core/src/index.ts | 28 +++- .../components}/CalloutNativeComponent.ts | 0 .../components}/FocusZoneNativeComponent.ts | 0 .../FocusZoneNativeComponent.win32.ts | 0 .../tests/native-ownership.test.mjs | 63 ++++++++ packages/agentic/native-core/tsconfig.json | 6 + .../native-core}/windows/.gitignore | 0 .../windows/ExperimentalFeatures.props | 0 .../windows/NativeCore/NativeCore.def} | 0 .../windows/NativeCore/NativeCore.vcxproj} | 16 +- .../NativeCore}/ReactPackageProvider.cpp | 9 +- .../NativeCore}/ReactPackageProvider.h | 8 +- .../NativeCore}/ReactPackageProvider.idl | 2 +- .../windows/NativeCore}/codegen/.clang-format | 2 +- .../components/FRNNativeCoreSpec}/Callout.g.h | 4 +- .../FRNNativeCoreSpec}/FocusZone.g.h | 4 +- .../components}/Callout/Callout.cpp | 0 .../NativeCore/components}/Callout/Callout.h | 4 +- .../FocusZone}/FocusZoneComponentView.cpp | 6 +- .../FocusZone}/FocusZoneComponentView.h | 0 .../windows/NativeCore}/packages.lock.json | 0 .../native-core/windows/NativeCore}/pch.cpp | 0 .../native-core/windows/NativeCore}/pch.h | 0 .../windows/NativeCore}/targetver.h | 0 .../native-core}/windows/NuGet.Config | 0 .../storybook-desktop-runtime/package.json | 4 +- .../src/Win32CalloutPortal.tsx | 4 +- .../storybook-desktop-runtime/tsconfig.json | 6 +- .../config/makeDesktopStorybookConfig.test.ts | 10 +- .../components/ContextualMenu/tsconfig.json | 4 +- .../components/FocusZone/RCTFocusZone.podspec | 21 --- .../FocusZone/react-native.config.cjs | 15 -- .../FocusZone/windows/FRNFocusZone.sln | 43 ----- .../windows/FRNFocusZone/FRNFocusZone.rc | Bin 160 -> 0 bytes .../FRNFocusZone/FRNFocusZone.vcxproj.filters | 44 ----- .../FocusZone/windows/FRNFocusZone/resource.h | 5 - packages/components/Menu/tsconfig.json | 4 +- packages/components/RadioGroup/tsconfig.json | 2 +- packages/components/TabList/tsconfig.json | 2 +- .../deprecated/foundation-compose/AGENTS.md | 2 +- packages/experimental/Dropdown/tsconfig.json | 2 +- packages/experimental/Tooltip/tsconfig.json | 2 +- packages/libraries/core/tsconfig.json | 4 +- packages/native/Callout/windows/.gitignore | 46 ------ .../Callout/windows/Callout/Callout.def | 3 - .../Callout/windows/Callout/Callout.vcxproj | 152 ------------------ .../windows/Callout/ReactPackageProvider.cpp | 25 --- .../windows/Callout/ReactPackageProvider.h | 25 --- .../windows/Callout/ReactPackageProvider.idl | 12 -- .../windows/Callout/codegen/.clang-format | 2 - .../windows/Callout/packages.lock.json | 151 ----------------- .../native/Callout/windows/Callout/pch.cpp | 1 - packages/native/Callout/windows/Callout/pch.h | 28 ---- .../windows/ExperimentalFeatures.props | 33 ---- packages/native/Callout/windows/NuGet.Config | 13 -- .../Callout => shim/callout}/CHANGELOG.json | 0 .../Callout => shim/callout}/CHANGELOG.md | 0 packages/shim/callout/README.md | 18 +++ .../Callout => shim/callout}/jest.config.cjs | 0 .../Callout => shim/callout}/package.json | 37 ++--- packages/shim/callout/src/index.test.ts | 22 +++ .../Callout => shim/callout}/src/index.ts | 5 +- .../Callout => shim/callout}/tsconfig.json | 2 +- .../focus-zone}/CHANGELOG.json | 0 .../focus-zone}/CHANGELOG.md | 0 packages/shim/focus-zone/README.md | 19 +++ packages/shim/focus-zone/jest.config.cjs | 1 + .../focus-zone}/package.json | 39 ++--- packages/shim/focus-zone/src/index.test.ts | 26 +++ .../focus-zone}/src/index.ts | 7 +- .../focus-zone}/tsconfig.json | 8 +- tsconfig.json | 8 +- yarn.lock | 62 +++++-- 128 files changed, 578 insertions(+), 881 deletions(-) create mode 100644 .changeset/native-core-component-migration.md rename packages/{native/Callout/FRNCallout.podspec => agentic/native-core/FRNNativeCore.podspec} (82%) rename packages/{native/Callout => agentic/native-core}/NuGet.config (100%) rename packages/{components/FocusZone => agentic/native-core}/jest.config.cjs (100%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/fabric}/RCTCalloutComponentView.h (100%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/fabric}/RCTCalloutComponentView.mm (95%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/paper}/CalloutManager.swift (100%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/paper}/FRNCalloutManager.h (100%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/paper}/FRNCalloutManager.m (98%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/shared}/CalloutView.swift (100%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/shared}/CalloutWindow.swift (100%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/shared}/FRNCallout.h (57%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/shared}/FlippedVisualEffectView.swift (100%) rename packages/{native/Callout/macos => agentic/native-core/macos/components/Callout/shared}/GuardedEventMonitor.swift (100%) rename packages/{components/FocusZone/macos => agentic/native-core/macos/components/FocusZone/fabric}/RCTFocusZoneComponentView.h (100%) rename packages/{components/FocusZone/macos => agentic/native-core/macos/components/FocusZone/fabric}/RCTFocusZoneComponentView.mm (94%) rename packages/{components/FocusZone/macos => agentic/native-core/macos/components/FocusZone/paper}/RCTFocusZoneManager.h (100%) rename packages/{components/FocusZone/macos => agentic/native-core/macos/components/FocusZone/paper}/RCTFocusZoneManager.m (97%) rename packages/{components/FocusZone/macos => agentic/native-core/macos/components/FocusZone/shared}/KeyCodes.h (100%) rename packages/{components/FocusZone/macos => agentic/native-core/macos/components/FocusZone/shared}/RCTFocusZone.h (100%) rename packages/{components/FocusZone/macos => agentic/native-core/macos/components/FocusZone/shared}/RCTFocusZone.m (100%) rename packages/{native/Callout => agentic/native-core}/react-native.config.cjs (78%) rename packages/{native/Callout/src => agentic/native-core/src/components/callout}/Callout.stories.tsx (100%) rename packages/{native/Callout/src => agentic/native-core/src/components/callout}/Callout.tsx (97%) rename packages/{native/Callout/src => agentic/native-core/src/components/callout}/Callout.types.ts (100%) rename packages/{native/Callout => agentic/native-core/src/components/callout}/SPEC.md (77%) rename packages/{native/Callout/src => agentic/native-core/src/components/callout}/__tests__/Callout.test.tsx (98%) rename packages/{native/Callout/src => agentic/native-core/src/components/callout}/__tests__/Callout.types.test.ts (100%) rename packages/{native/Callout/src => agentic/native-core/src/components/callout}/__tests__/__snapshots__/Callout.test.tsx.snap (100%) rename packages/{components/FocusZone/src => agentic/native-core/src/components/focus-zone}/FocusZone.tsx (96%) rename packages/{components/FocusZone/src => agentic/native-core/src/components/focus-zone}/FocusZone.types.ts (100%) rename packages/{components/FocusZone => agentic/native-core/src/components/focus-zone}/SPEC.md (83%) rename packages/{components/FocusZone/src => agentic/native-core/src/components/focus-zone}/__tests__/FocusZone.test.tsx (100%) rename packages/{components/FocusZone/src => agentic/native-core/src/components/focus-zone}/__tests__/FocusZone.types.test.ts (100%) rename packages/{native/Callout/src => agentic/native-core/src/specs/components}/CalloutNativeComponent.ts (100%) rename packages/{components/FocusZone/src => agentic/native-core/src/specs/components}/FocusZoneNativeComponent.ts (100%) rename packages/{components/FocusZone/src => agentic/native-core/src/specs/components}/FocusZoneNativeComponent.win32.ts (100%) create mode 100644 packages/agentic/native-core/tests/native-ownership.test.mjs rename packages/{components/FocusZone => agentic/native-core}/windows/.gitignore (100%) rename packages/{components/FocusZone => agentic/native-core}/windows/ExperimentalFeatures.props (100%) rename packages/{components/FocusZone/windows/FRNFocusZone/FRNFocusZone.def => agentic/native-core/windows/NativeCore/NativeCore.def} (100%) rename packages/{components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj => agentic/native-core/windows/NativeCore/NativeCore.vcxproj} (94%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/ReactPackageProvider.cpp (59%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/ReactPackageProvider.h (65%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/ReactPackageProvider.idl (87%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/codegen/.clang-format (50%) rename packages/{native/Callout/windows/Callout/codegen/react/components/FRNCalloutSpec => agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec}/Callout.g.h (99%) rename packages/{components/FocusZone/windows/FRNFocusZone/codegen/react/components/FRNFocusZoneSpec => agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec}/FocusZone.g.h (99%) rename packages/{native/Callout/windows => agentic/native-core/windows/NativeCore/components}/Callout/Callout.cpp (100%) rename packages/{native/Callout/windows => agentic/native-core/windows/NativeCore/components}/Callout/Callout.h (86%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore/components/FocusZone}/FocusZoneComponentView.cpp (98%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore/components/FocusZone}/FocusZoneComponentView.h (100%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/packages.lock.json (100%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/pch.cpp (100%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/pch.h (100%) rename packages/{components/FocusZone/windows/FRNFocusZone => agentic/native-core/windows/NativeCore}/targetver.h (100%) rename packages/{components/FocusZone => agentic/native-core}/windows/NuGet.Config (100%) delete mode 100644 packages/components/FocusZone/RCTFocusZone.podspec delete mode 100644 packages/components/FocusZone/react-native.config.cjs delete mode 100644 packages/components/FocusZone/windows/FRNFocusZone.sln delete mode 100644 packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.rc delete mode 100644 packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj.filters delete mode 100644 packages/components/FocusZone/windows/FRNFocusZone/resource.h delete mode 100644 packages/native/Callout/windows/.gitignore delete mode 100644 packages/native/Callout/windows/Callout/Callout.def delete mode 100644 packages/native/Callout/windows/Callout/Callout.vcxproj delete mode 100644 packages/native/Callout/windows/Callout/ReactPackageProvider.cpp delete mode 100644 packages/native/Callout/windows/Callout/ReactPackageProvider.h delete mode 100644 packages/native/Callout/windows/Callout/ReactPackageProvider.idl delete mode 100644 packages/native/Callout/windows/Callout/codegen/.clang-format delete mode 100644 packages/native/Callout/windows/Callout/packages.lock.json delete mode 100644 packages/native/Callout/windows/Callout/pch.cpp delete mode 100644 packages/native/Callout/windows/Callout/pch.h delete mode 100644 packages/native/Callout/windows/ExperimentalFeatures.props delete mode 100644 packages/native/Callout/windows/NuGet.Config rename packages/{native/Callout => shim/callout}/CHANGELOG.json (100%) rename packages/{native/Callout => shim/callout}/CHANGELOG.md (100%) create mode 100644 packages/shim/callout/README.md rename packages/{native/Callout => shim/callout}/jest.config.cjs (100%) rename packages/{native/Callout => shim/callout}/package.json (77%) create mode 100644 packages/shim/callout/src/index.test.ts rename packages/{native/Callout => shim/callout}/src/index.ts (60%) rename packages/{native/Callout => shim/callout}/tsconfig.json (87%) rename packages/{components/FocusZone => shim/focus-zone}/CHANGELOG.json (100%) rename packages/{components/FocusZone => shim/focus-zone}/CHANGELOG.md (100%) create mode 100644 packages/shim/focus-zone/README.md create mode 100644 packages/shim/focus-zone/jest.config.cjs rename packages/{components/FocusZone => shim/focus-zone}/package.json (74%) create mode 100644 packages/shim/focus-zone/src/index.test.ts rename packages/{components/FocusZone => shim/focus-zone}/src/index.ts (54%) rename packages/{components/FocusZone => shim/focus-zone}/tsconfig.json (65%) diff --git a/.changeset/modern-native-core.md b/.changeset/modern-native-core.md index 918f484f9b..e3bb7476d2 100644 --- a/.changeset/modern-native-core.md +++ b/.changeset/modern-native-core.md @@ -3,3 +3,5 @@ --- Initialize the native-core package with cross-platform, macOS, Windows, shared Windows/Win32, and Win32 entrypoints and a native component and TurboModule organization plan. + +Own the Callout and FocusZone JS wrappers, codegen specifications, macOS Paper/Fabric adapters, and Windows Fabric implementations in this shared package. diff --git a/.changeset/native-core-component-migration.md b/.changeset/native-core-component-migration.md new file mode 100644 index 0000000000..a4a72c2b51 --- /dev/null +++ b/.changeset/native-core-component-migration.md @@ -0,0 +1,9 @@ +--- +"@fluentui-react-native/callout": patch +"@fluentui-react-native/focus-zone": patch +"@fluentui-react-native/components": patch +"@fluentui-react-native/storybook-desktop-runtime": patch +"@fluentui-react-native/tester": patch +--- + +Move Callout and FocusZone implementations into native-core and retain the existing packages as JS-only compatibility shims under packages/shim. Native applications must directly depend on native-core and regenerate native autolinking/Pods; macOS now uses the shared FRNNativeCore pod and Windows uses one Fabric library for both components. Public APIs and native registration names are unchanged. diff --git a/.github/skills/agentic-component-authoring/references/focus-macos.md b/.github/skills/agentic-component-authoring/references/focus-macos.md index 1e9cf6184c..990010bb1a 100644 --- a/.github/skills/agentic-component-authoring/references/focus-macos.md +++ b/.github/skills/agentic-component-authoring/references/focus-macos.md @@ -31,8 +31,8 @@ focus visual should be presented as active. exposure or global numeric-tag lookup. Local references: -`packages\components\FocusZone\macos\RCTFocusZone.m:24-35,122-129`; -`packages\components\FocusZone\macos\RCTFocusZoneComponentView.mm:118-179`. +`packages\agentic\native-core\macos\components\FocusZone\shared\RCTFocusZone.m:24-35,122-129`; +`packages\agentic\native-core\macos\components\FocusZone\fabric\RCTFocusZoneComponentView.mm:118-179`. Installed RNmacOS `React\Fabric\Mounting\ComponentViews\View\RCTViewComponentView.mm:1719-1804` implements focus/blur commands and responder event emission. @@ -105,8 +105,8 @@ same keys. Recompute eligibility when children mount/unmount and when props change, and clear the default responder on recycle. Retain direction, wrap/stop, RTL, nested zones, scrolling, and editable-child semantics. -Evidence: `packages\components\FocusZone\macos\RCTFocusZone.m:584-675`; -`packages\components\FocusZone\macos\RCTFocusZoneComponentView.mm:118-195`. +Evidence: `packages\agentic\native-core\macos\components\FocusZone\shared\RCTFocusZone.m:584-675`; +`packages\agentic\native-core\macos\components\FocusZone\fabric\RCTFocusZoneComponentView.mm:118-195`. ## Popup windows and lifecycle @@ -131,10 +131,10 @@ Do not install OS-global keyboard hooks or require desktop-driver permissions for ordinary production focus behavior. Evidence: -`packages\native\Callout\macos\CalloutWindow.swift:9-38`; -`packages\native\Callout\macos\CalloutView.swift:33-45,142-216`; -`packages\native\Callout\macos\RCTCalloutComponentView.mm:96-132`; -`packages\native\Callout\macos\GuardedEventMonitor.swift:1-29`; +`packages\agentic\native-core\macos\components\Callout\shared\CalloutWindow.swift:9-38`; +`packages\agentic\native-core\macos\components\Callout\shared\CalloutView.swift:33-45,142-216`; +`packages\agentic\native-core\macos\components\Callout\fabric\RCTCalloutComponentView.mm:96-132`; +`packages\agentic\native-core\macos\components\Callout\shared\GuardedEventMonitor.swift:1-29`; `packages\components\ContextualMenu\src\ContextualMenu.tsx:39-55`. ## Native versus custom ring drawing diff --git a/.github/skills/agentic-component-authoring/references/focus-windows.md b/.github/skills/agentic-component-authoring/references/focus-windows.md index bcf96e3311..bd677f65cc 100644 --- a/.github/skills/agentic-component-authoring/references/focus-windows.md +++ b/.github/skills/agentic-component-authoring/references/focus-windows.md @@ -53,7 +53,7 @@ assume a React ref can be serialized into a TurboModule argument. The existing Fabric FocusZone uses `TryFocus(FocusState::Keyboard)` and checks the root's focused component after the request -(`packages\components\FocusZone\windows\FRNFocusZone\FocusZoneComponentView.cpp:175-224`). +(`packages\agentic\native-core\windows\NativeCore\components\FocusZone\FocusZoneComponentView.cpp:175-224`). Reuse this request-versus-observation pattern. Do not report success merely because JavaScript called an optional `.focus()` method. @@ -94,7 +94,7 @@ This native implementation detail is not a promised public JavaScript API. consume every key. Sources: `packages\utils\interactive-hooks\src\useKeyProps.ts:8-95,114-126`; -`packages\components\FocusZone\windows\FRNFocusZone\FocusZoneComponentView.cpp:71-133`. +`packages\agentic\native-core\windows\NativeCore\components\FocusZone\FocusZoneComponentView.cpp:71-133`. ## Native and custom focus visuals diff --git a/.gitignore b/.gitignore index c89077c9ea..d0ff6b78de 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,12 @@ apps/*/.vscode/.react/ # Visual Studio .vs/ +# Native library outputs, including caches left behind by workspace relocations +packages/**/windows/**/[Oo]bj/ +packages/**/windows/**/Generated Files/ +packages/**/windows/**/x64/[Dd]ebug*/ +packages/**/windows/**/x64/[Rr]elease*/ + # Ignore Gradle build output directory **/android/**/build diff --git a/.oxfmtrc.json b/.oxfmtrc.json index 78d5f13b9a..4750ea7dac 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -10,7 +10,7 @@ "**/*.generated.*", "**/lib-commonjs/**", "**/dist/**", - "packages/native/Callout/windows/Callout/codegen/**", + "packages/agentic/native-core/windows/NativeCore/codegen/**", "**/CHANGELOG.*", "**/CODE_OF_CONDUCT.md", "**/SECURITY.md", diff --git a/AGENTS.md b/AGENTS.md index b2d3381a1c..f05cbd3606 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -88,7 +88,7 @@ This is the **FluentUI React Native** repository, a monorepo containing React Na /packages/ - Core library packages /agentic/native-core/ - Shared modern native components and TurboModules /components/ - UI component implementations (Button, Checkbox, Avatar, etc.) - /native/ - Standalone native-backed component packages (Callout, etc.) + /shim/ - Compatibility entrypoints (Callout, FocusZone, theming, etc.) /framework/ - Core theming and composition framework /composition/ - Component composition factory (current approach) /theme/ - Theme system @@ -238,9 +238,9 @@ The composition framework uses precise types for better type safety: ### Component Development -**Component Location**: Stable JavaScript components are in `/packages/components/`, standalone native-backed components are in -`/packages/native/`, and components under development are in `/packages/experimental/`. New modern native components and -modules share `/packages/agentic/native-core/`; follow its [organization plan](packages/agentic/native-core/README.md). +**Component Location**: Stable JavaScript components are in `/packages/components/`, components under development are in +`/packages/experimental/`, and compatibility packages are in `/packages/shim/`. Modern native components and modules share +`/packages/agentic/native-core/`; follow its [organization plan](packages/agentic/native-core/README.md). **Component Structure**: Each component typically has: @@ -274,24 +274,24 @@ modules share `/packages/agentic/native-core/`; follow its [organization plan](p - **Do not use barrel exports (`export * from '...'`)** - wildcard re-exports break tree-shaking because bundlers cannot statically determine which symbols are used, so unused code is retained in consumers' bundles. Always use explicit named re-exports instead, e.g. `export { Foo, Bar } from './module'` and `export type { Baz } from './module'`. -**Native Modules**: Standalone native-backed component packages, such as Callout, live in `/packages/native/`. Components with -native code (iOS/Android/Windows): +**Native Modules**: Callout and FocusZone implementations live in `@fluentui-react-native/native-core`; their former packages +are JS-only compatibility shims under `/packages/shim/`. Components with native code: - Typically have one root slot wrapping the native component - Use `codegenNativeComponent` for new architecture compatibility - May use `constantsToExport` for default values from native side - iOS/macOS: Include `.podspec` files -- Must be added to FluentTester's Podfile (transitive dependencies aren't autolinked) +- Native applications must directly depend on native-core for native project discovery and autolinking For new modern native components and modules, use `@fluentui-react-native/native-core` rather than creating another standalone package. Its Windows components are Fabric-only; macOS components support Paper and Fabric initially. Export shared APIs from the root and scope platform APIs to `macos`, `windows` (React Native Windows), `win` (Windows/Win32), or `win32`. -Existing native packages are not migrated by this convention. +Callout and FocusZone retain their existing public APIs and native registration names after migration. ### Creating a New Component -1. Create the package under `/packages/components/`, `/packages/native/` for a standalone - native-backed component, or `/packages/experimental/` while it is under development +1. Create the package under `/packages/components/` or `/packages/experimental/` while it is + under development. Add modern native components/modules to the existing `/packages/agentic/native-core/` package instead. 2. Copy structure from existing component (e.g., Shimmer, Button) 3. Update `package.json` with correct name and dependencies (use `workspace:*` for internal packages) 4. Add the new package's `tsconfig.json` to the root `tsconfig.json` `references` so it joins the unified build diff --git a/apps/E2E/tsconfig.json b/apps/E2E/tsconfig.json index 97bea26d4a..55864b6fde 100644 --- a/apps/E2E/tsconfig.json +++ b/apps/E2E/tsconfig.json @@ -10,7 +10,7 @@ "include": ["src"], "references": [ { - "path": "../../packages/components/FocusZone/tsconfig.json" + "path": "../../packages/shim/focus-zone/tsconfig.json" }, { "path": "../../scripts/tsconfig.json" diff --git a/apps/fluent-tester/package.json b/apps/fluent-tester/package.json index 71f307224c..dad808e8dc 100644 --- a/apps/fluent-tester/package.json +++ b/apps/fluent-tester/package.json @@ -38,6 +38,7 @@ "windows": "react-native run-windows --arch x64 --sln windows/FluentTester.sln" }, "dependencies": { + "@fluentui-react-native/native-core": "workspace:*", "@types/node": "catalog:", "@types/react": "~19.1.4", "react": "19.1.4", diff --git a/apps/fluent-tester/tsconfig.json b/apps/fluent-tester/tsconfig.json index 23bace6b87..ae103d0427 100644 --- a/apps/fluent-tester/tsconfig.json +++ b/apps/fluent-tester/tsconfig.json @@ -11,7 +11,7 @@ "include": ["src"], "references": [ { - "path": "../../packages/native/Callout/tsconfig.json" + "path": "../../packages/shim/callout/tsconfig.json" }, { "path": "../../packages/experimental/AppearanceAdditions/tsconfig.json" @@ -32,11 +32,14 @@ "path": "../../packages/experimental/Shimmer/tsconfig.json" }, { - "path": "../../packages/components/FocusZone/tsconfig.json" + "path": "../../packages/shim/focus-zone/tsconfig.json" }, { "path": "../../packages/components/MenuButton/tsconfig.json" }, + { + "path": "../../packages/agentic/native-core/tsconfig.json" + }, { "path": "../../packages/components/RadioGroup/tsconfig.json" }, diff --git a/apps/storybook/README.md b/apps/storybook/README.md index b24ae09060..ee18b76a50 100644 --- a/apps/storybook/README.md +++ b/apps/storybook/README.md @@ -1,10 +1,10 @@ # Agentic Components Storybook On-device [Storybook](https://storybook.js.org/) test app (Storybook for React Native v10) for -`@fluentui-react-native/components` and linked standalone native packages. It loads every -`*.stories.(ts|tsx)` file from the agentic components package plus the standalone Callout -package. FocusZone stories are agentic primitive stories, while its standalone native package -remains linked so they run in the Fabric and Paper hosts. +`@fluentui-react-native/components` and `@fluentui-react-native/native-core`. It loads every +`*.stories.(ts|tsx)` file from the agentic components package plus native-core's Callout +stories. FocusZone stories remain agentic primitive stories and use native-core's implementation. +Native-core owns the shared macOS pod and Windows Fabric library for both components. The reusable desktop CLI and configuration live in `packages/agentic/storybook-desktop`, with peer-dependent React Native @@ -129,9 +129,9 @@ by smoke so its bundle identity does not fall back to the generated app default. ## Running on Windows The Windows app also uses `react-native-test-app`. Its generated Win32 project uses React Native -Windows 0.81's New Architecture and Fabric renderer. The Callout and FocusZone packages are -autolinked as Windows Fabric native libraries; their Paper implementations remain available on -their supported legacy endpoints. +Windows 0.81's New Architecture and Fabric renderer. Native-core is autolinked as one Windows +Fabric native library that registers Callout and FocusZone. macOS retains both Paper and Fabric +adapters; Win32 continues using its host-provided native implementations. ```powershell # from this directory diff --git a/apps/storybook/agent-map.yaml b/apps/storybook/agent-map.yaml index df305c7a80..8039f0170e 100644 --- a/apps/storybook/agent-map.yaml +++ b/apps/storybook/agent-map.yaml @@ -15,7 +15,7 @@ sources: policy: generated-do-not-edit story_packages: - '@fluentui-react-native/components' - - '@fluentui-react-native/callout' + - '@fluentui-react-native/native-core' services: supervisor: diff --git a/apps/storybook/package.json b/apps/storybook/package.json index 4903ff03a7..13f134e41c 100644 --- a/apps/storybook/package.json +++ b/apps/storybook/package.json @@ -20,9 +20,8 @@ "format": "fluentui-scripts format" }, "dependencies": { - "@fluentui-react-native/callout": "workspace:*", "@fluentui-react-native/components": "workspace:*", - "@fluentui-react-native/focus-zone": "workspace:*", + "@fluentui-react-native/native-core": "workspace:*", "@fluentui-react-native/storybook-desktop": "workspace:*", "@fluentui-react-native/storybook-desktop-runtime": "workspace:*", "@office-iss/react-native-win32": "^0.81.0", @@ -57,9 +56,8 @@ "furn": { "knip": { "ignoreDependencies": [ - "@fluentui-react-native/callout", "@fluentui-react-native/components", - "@fluentui-react-native/focus-zone", + "@fluentui-react-native/native-core", "react-native-svg" ] } diff --git a/apps/storybook/storybook.config.mts b/apps/storybook/storybook.config.mts index a2c8541084..6284425899 100644 --- a/apps/storybook/storybook.config.mts +++ b/apps/storybook/storybook.config.mts @@ -29,7 +29,7 @@ export default makeDesktopStorybookConfig({ }, ], [ - '@fluentui-react-native/callout', + '@fluentui-react-native/native-core', { platformSettings: { windows: { diff --git a/apps/storybook/tsconfig.json b/apps/storybook/tsconfig.json index 2e379f55aa..3ce850c19e 100644 --- a/apps/storybook/tsconfig.json +++ b/apps/storybook/tsconfig.json @@ -16,16 +16,13 @@ "exclude": ["node_modules", "dist", ".cache"], "references": [ { - "path": "../../packages/agentic/storybook-desktop/tsconfig.json" - }, - { - "path": "../../packages/native/Callout/tsconfig.json" + "path": "../../packages/agentic/components/tsconfig.json" }, { - "path": "../../packages/agentic/components/tsconfig.json" + "path": "../../packages/agentic/desktop-driver/tsconfig.json" }, { - "path": "../../packages/components/FocusZone/tsconfig.json" + "path": "../../packages/agentic/native-core/tsconfig.json" }, { "path": "../../scripts/tsconfig.json" @@ -34,7 +31,7 @@ "path": "../../packages/agentic/storybook-desktop-runtime/tsconfig.json" }, { - "path": "../../packages/agentic/desktop-driver/tsconfig.json" + "path": "../../packages/agentic/storybook-desktop/tsconfig.json" } ] } diff --git a/apps/tester-core/tsconfig.json b/apps/tester-core/tsconfig.json index 7757310289..ee6c375fcf 100644 --- a/apps/tester-core/tsconfig.json +++ b/apps/tester-core/tsconfig.json @@ -29,7 +29,7 @@ "path": "../../packages/components/Button/tsconfig.json" }, { - "path": "../../packages/native/Callout/tsconfig.json" + "path": "../../packages/shim/callout/tsconfig.json" }, { "path": "../../packages/components/Chip/tsconfig.json" @@ -83,7 +83,7 @@ "path": "../../packages/experimental/Shimmer/tsconfig.json" }, { - "path": "../../packages/components/FocusZone/tsconfig.json" + "path": "../../packages/shim/focus-zone/tsconfig.json" }, { "path": "../../packages/framework-base/tsconfig.json" diff --git a/packages/agentic/components/WIN32-FOCUS-PLAN.md b/packages/agentic/components/WIN32-FOCUS-PLAN.md index ce765d75f6..c857fe0509 100644 --- a/packages/agentic/components/WIN32-FOCUS-PLAN.md +++ b/packages/agentic/components/WIN32-FOCUS-PLAN.md @@ -246,7 +246,7 @@ paths. The installed Win32 JavaScript inspected was `packages\components\Menu\src\MenuPopover\useMenuPopover.ts:42-84,100-118`. - **V6:** `packages\components\TabList\src\Tab\useTab.win32.ts:64-110,142-152`; `packages\components\TabList\src\TabList\useTabList.ts:142-176,183-200`. -- **V7:** `packages\components\FocusZone\src\FocusZone.tsx:15-45`; +- **V7:** `packages\agentic\native-core\src\components\focus-zone\FocusZone.tsx:15-45`; `packages\components\FocusTrapZone\src\FocusTrapZone.ts:15-31`. These wrappers do not by themselves prove native trap/restoration semantics. - **V8:** `apps\tester-core\src\TestComponents\FocusZone\FocusZoneE2ETest.tsx:1-120`; @@ -297,7 +297,7 @@ paths. The installed Win32 JavaScript inspected was ### Added Fabric, macOS, and modern-ref evidence -- **W1:** `packages\components\FocusZone\windows\FRNFocusZone\FocusZoneComponentView.cpp:33-65,71-133,175-224` +- **W1:** `packages\agentic\native-core\windows\NativeCore\components\FocusZone\FocusZoneComponentView.cpp:33-65,71-133,175-224` subscribes to native focus/key events, requests `TryFocus(FocusState::Keyboard)`, and checks actual focused identity. This is a Fabric implementation model for V1 outcomes, not a reason to copy its transport to Win32. @@ -316,18 +316,18 @@ paths. The installed Win32 JavaScript inspected was implements AppKit focus/blur, ring-mask drawing, responder events, and pointer focus behavior. Lines 1807-1861 emit key events and use native handled-key entries to decide whether AppKit receives `super` handling. -- **M3:** `packages\components\FocusZone\macos\RCTFocusZone.m:24-35,122-129,584-675` +- **M3:** `packages\agentic\native-core\macos\components\FocusZone\shared\RCTFocusZone.m:24-35,122-129,584-675` resolves editable focus targets and key-view navigation, including a hierarchy fallback for Fabric-backed zones. - `packages\components\FocusZone\macos\RCTFocusZoneComponentView.mm:118-195` + `packages\agentic\native-core\macos\components\FocusZone\fabric\RCTFocusZoneComponentView.mm:118-195` forwards focus to its content rather than becoming a duplicate tab stop and clears default-responder state on recycle. -- **M4:** `packages\native\Callout\macos\CalloutWindow.swift:9-38`; - `packages\native\Callout\macos\CalloutView.swift:33-45,142-216`; - `packages\native\Callout\macos\RCTCalloutComponentView.mm:96-132`. +- **M4:** `packages\agentic\native-core\macos\components\Callout\shared\CalloutWindow.swift:9-38`; + `packages\agentic\native-core\macos\components\Callout\shared\CalloutView.swift:33-45,142-216`; + `packages\agentic\native-core\macos\components\Callout\fabric\RCTCalloutComponentView.mm:96-132`. Popup key-window activation, initial child focus, and a separate Fabric touch attachment are distinct concerns. - `packages\native\Callout\macos\GuardedEventMonitor.swift:1-29` owns monitor cleanup. + `packages\agentic\native-core\macos\components\Callout\shared\GuardedEventMonitor.swift:1-29` owns monitor cleanup. - **M5:** `packages\components\ContextualMenu\src\ContextualMenu.tsx:39-55` contains a macOS layout-effect/timer workaround: a readiness problem to solve, not a general timer recipe. @@ -341,7 +341,7 @@ paths. The installed Win32 JavaScript inspected was covers stable native refs and compatible replacements. - **R2:** `packages\agentic\components\src\refs.types.test.tsx:30-84` distinguishes structural and pressable root refs. - `packages\native\Callout\src\CalloutNativeComponent.ts:63-70` demonstrates + `packages\agentic\native-core\src\specs\components\CalloutNativeComponent.ts:63-70` demonstrates typed native commands with host refs rather than global tag arguments. ### macOS adaptation decisions diff --git a/packages/agentic/components/package.json b/packages/agentic/components/package.json index 5a5783aa18..846c5c4527 100644 --- a/packages/agentic/components/package.json +++ b/packages/agentic/components/package.json @@ -40,14 +40,13 @@ "update-snapshots": "fluentui-scripts jest -u" }, "dependencies": { - "@fluentui-react-native/callout": "workspace:*", "@fluentui-react-native/design": "workspace:*", - "@fluentui-react-native/framework-base": "workspace:*" + "@fluentui-react-native/framework-base": "workspace:*", + "@fluentui-react-native/native-core": "workspace:*" }, "devDependencies": { "@babel/core": "catalog:", "@fluentui-react-native/desktop-driver": "workspace:*", - "@fluentui-react-native/focus-zone": "workspace:*", "@fluentui-react-native/scripts": "workspace:*", "@fluentui-react-native/storybook-desktop": "workspace:*", "@office-iss/react-native-win32": "^0.81.0", @@ -94,7 +93,7 @@ "jestPlatform": "macos", "knip": { "ignoreDependencies": [ - "@fluentui-react-native/callout" + "@fluentui-react-native/native-core" ] } }, diff --git a/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx b/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx index bb86787ff3..2463df8fe9 100644 --- a/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx +++ b/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx @@ -4,8 +4,8 @@ import { Platform, Pressable, StyleSheet, Text, View } from 'react-native'; import type { StyleProp, ViewStyle } from 'react-native'; import type { WdioStory } from '@fluentui-react-native/storybook-desktop/testing'; -import { FocusZone } from '@fluentui-react-native/focus-zone'; -import type { FocusZoneDirection, FocusZoneProps, FocusZoneTabNavigation } from '@fluentui-react-native/focus-zone'; +import { FocusZone } from '@fluentui-react-native/native-core'; +import type { FocusZoneDirection, FocusZoneProps, FocusZoneTabNavigation } from '@fluentui-react-native/native-core'; import type { Meta, StoryObj } from '@storybook/react-native'; import { Button } from '../../components/button/button'; diff --git a/packages/agentic/components/tsconfig.json b/packages/agentic/components/tsconfig.json index 1b9942a25a..965178a7ed 100644 --- a/packages/agentic/components/tsconfig.json +++ b/packages/agentic/components/tsconfig.json @@ -9,9 +9,6 @@ "include": ["src"], "exclude": ["**/*.stories.ts", "**/*.stories.tsx", "**/*.story-helpers.tsx", "**/*.wdio.ts"], "references": [ - { - "path": "../../native/Callout/tsconfig.json" - }, { "path": "../design/tsconfig.json" }, @@ -19,16 +16,16 @@ "path": "../desktop-driver/tsconfig.json" }, { - "path": "../storybook-desktop/tsconfig.json" + "path": "../../framework-base/tsconfig.json" }, { - "path": "../../components/FocusZone/tsconfig.json" + "path": "../native-core/tsconfig.json" }, { - "path": "../../framework-base/tsconfig.json" + "path": "../../../scripts/tsconfig.json" }, { - "path": "../../../scripts/tsconfig.json" + "path": "../storybook-desktop/tsconfig.json" } ] } diff --git a/packages/native/Callout/FRNCallout.podspec b/packages/agentic/native-core/FRNNativeCore.podspec similarity index 82% rename from packages/native/Callout/FRNCallout.podspec rename to packages/agentic/native-core/FRNNativeCore.podspec index 5a46aedb2a..3165e1234c 100644 --- a/packages/native/Callout/FRNCallout.podspec +++ b/packages/agentic/native-core/FRNNativeCore.podspec @@ -3,8 +3,8 @@ require 'json' package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) Pod::Spec.new do |s| - s.name = 'FRNCallout' - s.module_name = 'FRNCallout' + s.name = 'FRNNativeCore' + s.module_name = 'FRNNativeCore' s.version = package['version'] s.summary = package['description'] s.license = package['license'] @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.swift_version = "5" s.osx.deployment_target = "10.15" - s.osx.source_files = "macos/*.{swift,h,m,mm}" + s.osx.source_files = "macos/**/*.{swift,h,m,mm}" s.dependency 'React' diff --git a/packages/native/Callout/NuGet.config b/packages/agentic/native-core/NuGet.config similarity index 100% rename from packages/native/Callout/NuGet.config rename to packages/agentic/native-core/NuGet.config diff --git a/packages/agentic/native-core/README.md b/packages/agentic/native-core/README.md index 5816756caf..d1dba69b34 100644 --- a/packages/agentic/native-core/README.md +++ b/packages/agentic/native-core/README.md @@ -7,18 +7,25 @@ Higher-order Fluent components, theming, and composition remain in their existing packages and can consume this package without introducing a reverse dependency. -## Initialization status - -The workspace, TypeScript build, package export map, and entrypoint contract -tests are initialized. All five entrypoints are intentionally empty. There are -no native implementations, codegen specs, native projects, or autolinking -registrations yet. This does not migrate Callout, FocusZone, or any other -existing package. - -The initial shell has no runtime dependencies. Add React Native/React peers, -optional platform-fork peers, development dependencies, and matching `rnx-kit` -capabilities with the first implementation, using the repository's supported -versions. Do not imply native compatibility from an empty entrypoint. +## Current contents + +The root exports the existing unstyled `Callout` and `FocusZone` wrappers and +their public types. Their JS, tests, specifications, macOS implementations, +and Windows Fabric implementations live here. The `macos`, `windows`, `win`, +and `win32` entrypoints are reserved for future host-specific APIs and remain +empty; shared components belong to the root. + +`@fluentui-react-native/callout` and `@fluentui-react-native/focus-zone` are +JS-only compatibility shims under `packages/shim`. Deprecated type aliases and +native registration names are preserved. The root uses the component-qualified +`FocusZoneNativeProps`; the FocusZone shim retains its old `NativeProps` name. + +Native applications must directly depend on this package for autolinking. +macOS now uses one `FRNNativeCore` pod, and Windows uses one +`FRNNativeCore.ReactPackageProvider` library for both components. Remove +explicit old `FRNCallout`/`RCTFocusZone` pod or standalone Windows project +references and regenerate the consuming native project/Pods. Win32 continues +to use its host-provided `RCTCallout` and `RCTFocusZone`. ## Public entrypoints @@ -50,8 +57,9 @@ imports. Never use wildcard re-exports. ## JavaScript and specification layout -Only the entrypoint files exist initially. Add the following directories as -real features arrive rather than filling them with placeholder native APIs: +Component wrappers live in `src/components/callout` and +`src/components/focus-zone`, with codegen inputs in `src/specs/components`. +Add module and internal utility directories as real features arrive: ```text src/ @@ -148,15 +156,16 @@ and expose native failures. ## Codegen, registration, and publishing plan -Introduce native build metadata with the first real schema and native target: +The shared native build metadata follows this organization: 1. Use one package-level codegen identity, `FRNNativeCoreSpec`, with `type: "all"` and `jsSrcsDir: "src/specs"` so components and modules remain distinct in source but share a generation boundary. 2. Name component schemas `NativeComponent.ts` and module schemas `Native.ts`. Prefix native registration names with `FRNNativeCore` - to avoid collisions with existing packages; keep each name identical in - the schema, generated interface, native registration, and JS binding. + for new APIs to avoid collisions. Migrated Callout and FocusZone retain + their existing Fabric and Paper names for compatibility. Keep names + identical in the schema, generated interface, registration, and JS binding. 3. Configure Windows with both `componentsWindows` and `modulesWindows` generators and `windows/NativeCore/codegen` output. Apple codegen should run through the consuming macOS app's Pod integration. Inspect each @@ -165,12 +174,13 @@ Introduce native build metadata with the first real schema and native target: 4. Leave `includesGeneratedCode` unset unless generated artifacts for every supported native platform are deliberately shipped and verified. It is not a Windows-only switch and can prevent Apple code generation. -5. Add the macOS podspec, Windows project/provider, and autolinking metadata - only when they refer to real sources. Exclude Paper adapters from macOS - Fabric compilation and Fabric adapters from Paper compilation. Register - only implementations supported by the active host/architecture. +5. The macOS podspec includes both components' shared and Paper sources. + Fabric component views retain their `RCT_NEW_ARCH_ENABLED` guards. Paper + managers remain available for existing bridge interoperability until the + supported macOS hosts are Fabric-only. Windows declares `RnwNewArchOnly` + and registers both components through one package provider. 6. Keep native targets and required generated outputs in the published - archive. The initial `files` allowlist reserves `src`, `lib`, `macos`, + archive. The `files` allowlist includes `src`, `lib`, `macos`, `windows`, `win32`, podspecs, and `react-native.config.cjs`. Intermediate native build artifacts, tests, and machine-local project output must not leak into it. @@ -181,8 +191,9 @@ Introduce native build metadata with the first real schema and native target: ## Delivery and validation Add each feature as one reviewed contract, thin wrapper/schema, native -implementation, explicit export, and tests. Start with one representative -Fabric component and one TurboModule to exercise both codegen paths. +implementation, explicit export, and tests. The component codegen path is +exercised by Callout and FocusZone; add a representative TurboModule before +claiming module readiness. macOS component admission requires both Paper and Fabric evidence; Windows component admission requires Fabric evidence. A `win` or root API also requires Win32 evidence before it is exported there. @@ -194,12 +205,15 @@ yarn workspace @fluentui-react-native/native-core format --check yarn workspace @fluentui-react-native/native-core lint yarn workspace @fluentui-react-native/native-core build yarn workspace @fluentui-react-native/native-core test +yarn workspace @fluentui-react-native/native-core codegen:windows --check yarn build ``` -The initial Node tests validate all five export maps, emitted JS/declaration -files, and conditional resolution for compiled, React Native source, and -TypeScript entrypoints. Add the repository's shared Jest configuration and -native integration tests when wrappers and native targets exist. Native +Node tests validate the five export maps, emitted JS/declaration files, +conditional resolution, shared native ownership, and JS-only shims. Colocated +Jest tests retain wrapper behavior, imperative refs/commands, slot acceptance, +and public type contracts; shim tests verify exact component identity. +The package prebuild regenerates Windows bindings from the shared spec. +Native verification must cover registration, events/commands, refs, unmount cleanup, error propagation, and architecture/platform parity, not only JS mocks. diff --git a/packages/components/FocusZone/jest.config.cjs b/packages/agentic/native-core/jest.config.cjs similarity index 100% rename from packages/components/FocusZone/jest.config.cjs rename to packages/agentic/native-core/jest.config.cjs diff --git a/packages/native/Callout/macos/RCTCalloutComponentView.h b/packages/agentic/native-core/macos/components/Callout/fabric/RCTCalloutComponentView.h similarity index 100% rename from packages/native/Callout/macos/RCTCalloutComponentView.h rename to packages/agentic/native-core/macos/components/Callout/fabric/RCTCalloutComponentView.h diff --git a/packages/native/Callout/macos/RCTCalloutComponentView.mm b/packages/agentic/native-core/macos/components/Callout/fabric/RCTCalloutComponentView.mm similarity index 95% rename from packages/native/Callout/macos/RCTCalloutComponentView.mm rename to packages/agentic/native-core/macos/components/Callout/fabric/RCTCalloutComponentView.mm index 86a6d5a259..2dee187651 100644 --- a/packages/native/Callout/macos/RCTCalloutComponentView.mm +++ b/packages/agentic/native-core/macos/components/Callout/fabric/RCTCalloutComponentView.mm @@ -2,10 +2,10 @@ #import "RCTCalloutComponentView.h" -#import -#import -#import -#import +#import +#import +#import +#import #import #import @@ -13,7 +13,7 @@ #import #import -#import "FRNCallout-Swift.h" +#import "FRNNativeCore-Swift.h" using namespace facebook::react; diff --git a/packages/native/Callout/macos/CalloutManager.swift b/packages/agentic/native-core/macos/components/Callout/paper/CalloutManager.swift similarity index 100% rename from packages/native/Callout/macos/CalloutManager.swift rename to packages/agentic/native-core/macos/components/Callout/paper/CalloutManager.swift diff --git a/packages/native/Callout/macos/FRNCalloutManager.h b/packages/agentic/native-core/macos/components/Callout/paper/FRNCalloutManager.h similarity index 100% rename from packages/native/Callout/macos/FRNCalloutManager.h rename to packages/agentic/native-core/macos/components/Callout/paper/FRNCalloutManager.h diff --git a/packages/native/Callout/macos/FRNCalloutManager.m b/packages/agentic/native-core/macos/components/Callout/paper/FRNCalloutManager.m similarity index 98% rename from packages/native/Callout/macos/FRNCalloutManager.m rename to packages/agentic/native-core/macos/components/Callout/paper/FRNCalloutManager.m index ca5ebd4b58..f162f6cc3b 100644 --- a/packages/native/Callout/macos/FRNCalloutManager.m +++ b/packages/agentic/native-core/macos/components/Callout/paper/FRNCalloutManager.m @@ -1,6 +1,6 @@ #import "FRNCalloutManager.h" -#import "FRNCallout-Swift.h" +#import "FRNNativeCore-Swift.h" @implementation RCTConvert (FRNCalloutAdditions) diff --git a/packages/native/Callout/macos/CalloutView.swift b/packages/agentic/native-core/macos/components/Callout/shared/CalloutView.swift similarity index 100% rename from packages/native/Callout/macos/CalloutView.swift rename to packages/agentic/native-core/macos/components/Callout/shared/CalloutView.swift diff --git a/packages/native/Callout/macos/CalloutWindow.swift b/packages/agentic/native-core/macos/components/Callout/shared/CalloutWindow.swift similarity index 100% rename from packages/native/Callout/macos/CalloutWindow.swift rename to packages/agentic/native-core/macos/components/Callout/shared/CalloutWindow.swift diff --git a/packages/native/Callout/macos/FRNCallout.h b/packages/agentic/native-core/macos/components/Callout/shared/FRNCallout.h similarity index 57% rename from packages/native/Callout/macos/FRNCallout.h rename to packages/agentic/native-core/macos/components/Callout/shared/FRNCallout.h index a938f891a5..86c796ed89 100644 --- a/packages/native/Callout/macos/FRNCallout.h +++ b/packages/agentic/native-core/macos/components/Callout/shared/FRNCallout.h @@ -4,7 +4,7 @@ // // Created by Patrick Boyd on 9/24/24. // -// Created as a dummy file to enable importing FRNCallout-Swift.h and invoking Swift functions from Obj-C +// Created as a dummy file to enable importing FRNNativeCore-Swift.h and invoking Swift functions from Obj-C // #ifndef FRNCallout_h diff --git a/packages/native/Callout/macos/FlippedVisualEffectView.swift b/packages/agentic/native-core/macos/components/Callout/shared/FlippedVisualEffectView.swift similarity index 100% rename from packages/native/Callout/macos/FlippedVisualEffectView.swift rename to packages/agentic/native-core/macos/components/Callout/shared/FlippedVisualEffectView.swift diff --git a/packages/native/Callout/macos/GuardedEventMonitor.swift b/packages/agentic/native-core/macos/components/Callout/shared/GuardedEventMonitor.swift similarity index 100% rename from packages/native/Callout/macos/GuardedEventMonitor.swift rename to packages/agentic/native-core/macos/components/Callout/shared/GuardedEventMonitor.swift diff --git a/packages/components/FocusZone/macos/RCTFocusZoneComponentView.h b/packages/agentic/native-core/macos/components/FocusZone/fabric/RCTFocusZoneComponentView.h similarity index 100% rename from packages/components/FocusZone/macos/RCTFocusZoneComponentView.h rename to packages/agentic/native-core/macos/components/FocusZone/fabric/RCTFocusZoneComponentView.h diff --git a/packages/components/FocusZone/macos/RCTFocusZoneComponentView.mm b/packages/agentic/native-core/macos/components/FocusZone/fabric/RCTFocusZoneComponentView.mm similarity index 94% rename from packages/components/FocusZone/macos/RCTFocusZoneComponentView.mm rename to packages/agentic/native-core/macos/components/FocusZone/fabric/RCTFocusZoneComponentView.mm index 2905eb6fbb..8326d4d086 100644 --- a/packages/components/FocusZone/macos/RCTFocusZoneComponentView.mm +++ b/packages/agentic/native-core/macos/components/FocusZone/fabric/RCTFocusZoneComponentView.mm @@ -2,14 +2,14 @@ #import "RCTFocusZoneComponentView.h" -#import -#import -#import -#import +#import +#import +#import +#import #import -#import "RCTFocusZone.h" +#import "../shared/RCTFocusZone.h" using namespace facebook::react; diff --git a/packages/components/FocusZone/macos/RCTFocusZoneManager.h b/packages/agentic/native-core/macos/components/FocusZone/paper/RCTFocusZoneManager.h similarity index 100% rename from packages/components/FocusZone/macos/RCTFocusZoneManager.h rename to packages/agentic/native-core/macos/components/FocusZone/paper/RCTFocusZoneManager.h diff --git a/packages/components/FocusZone/macos/RCTFocusZoneManager.m b/packages/agentic/native-core/macos/components/FocusZone/paper/RCTFocusZoneManager.m similarity index 97% rename from packages/components/FocusZone/macos/RCTFocusZoneManager.m rename to packages/agentic/native-core/macos/components/FocusZone/paper/RCTFocusZoneManager.m index 68b93f136b..7d4eddaa48 100644 --- a/packages/components/FocusZone/macos/RCTFocusZoneManager.m +++ b/packages/agentic/native-core/macos/components/FocusZone/paper/RCTFocusZoneManager.m @@ -1,4 +1,4 @@ -#import "RCTFocusZone.h" +#import "../shared/RCTFocusZone.h" #import "RCTFocusZoneManager.h" #import #import diff --git a/packages/components/FocusZone/macos/KeyCodes.h b/packages/agentic/native-core/macos/components/FocusZone/shared/KeyCodes.h similarity index 100% rename from packages/components/FocusZone/macos/KeyCodes.h rename to packages/agentic/native-core/macos/components/FocusZone/shared/KeyCodes.h diff --git a/packages/components/FocusZone/macos/RCTFocusZone.h b/packages/agentic/native-core/macos/components/FocusZone/shared/RCTFocusZone.h similarity index 100% rename from packages/components/FocusZone/macos/RCTFocusZone.h rename to packages/agentic/native-core/macos/components/FocusZone/shared/RCTFocusZone.h diff --git a/packages/components/FocusZone/macos/RCTFocusZone.m b/packages/agentic/native-core/macos/components/FocusZone/shared/RCTFocusZone.m similarity index 100% rename from packages/components/FocusZone/macos/RCTFocusZone.m rename to packages/agentic/native-core/macos/components/FocusZone/shared/RCTFocusZone.m diff --git a/packages/agentic/native-core/package.json b/packages/agentic/native-core/package.json index 6542e731eb..408487ba1f 100644 --- a/packages/agentic/native-core/package.json +++ b/packages/agentic/native-core/package.json @@ -15,8 +15,19 @@ "macos", "windows", "win32", + "NuGet.config", "*.podspec", - "react-native.config.cjs" + "react-native.config.cjs", + "!src/**/__tests__/**", + "!src/**/*.test.*", + "!lib/**/__tests__/**", + "!lib/**/*.test.*", + "!windows/**/obj/**", + "!windows/**/x64/**", + "!windows/**/ARM64/**", + "!windows/**/Win32/**", + "!windows/**/Generated Files/**", + "!windows/**/packages/**" ], "type": "module", "sideEffects": false, @@ -59,15 +70,105 @@ "scripts": { "build": "tsc -b", "clean": "fluentui-scripts clean", + "codegen:windows": "react-native codegen-windows --no-telemetry", "format": "fluentui-scripts format", "lint": "fluentui-scripts lint", - "test": "yarn build && node --test tests/entrypoints.test.mjs" + "prebuild": "yarn codegen:windows", + "test": "yarn build && node --test tests/entrypoints.test.mjs tests/native-ownership.test.mjs && fluentui-scripts jest", + "update-snapshots": "fluentui-scripts jest -u" + }, + "dependencies": { + "@fluentui-react-native/framework-base": "workspace:*", + "@fluentui-react-native/interactive-hooks": "workspace:*" }, "devDependencies": { - "@fluentui-react-native/scripts": "workspace:*" + "@babel/core": "catalog:", + "@fluentui-react-native/scripts": "workspace:*", + "@office-iss/react-native-win32": "^0.81.8", + "@react-native-community/cli": "^20.0.0", + "@react-native-community/cli-platform-android": "^20.0.0", + "@react-native-community/cli-platform-ios": "^20.0.0", + "@react-native-windows/cli": "^0.81.0", + "@react-native/babel-preset": "^0.81.0", + "@react-native/metro-config": "^0.81.0", + "@storybook/react-native": "^10.4.7", + "@testing-library/react-native": "catalog:", + "@types/react": "~19.1.4", + "@types/react-test-renderer": "^19.1.0", + "react": "19.1.4", + "react-native": "^0.81.6", + "react-native-macos": "^0.81.0", + "react-native-windows": "^0.81.0", + "react-test-renderer": "19.1.4", + "storybook": "^10.4.0", + "test-renderer": "catalog:" + }, + "peerDependencies": { + "@office-iss/react-native-win32": "^0.74.0 || ^0.81.0", + "@types/react": "~18.2.0 || ~19.0.0 || ~19.1.4", + "react": "18.2.0 || 19.0.0 || 19.1.4", + "react-native": "^0.73.0 || ^0.74.0 || ^0.78.0 || ^0.81.6", + "react-native-macos": "^0.73.0 || ^0.74.0 || ^0.78.0 || ^0.81.0", + "react-native-windows": "^0.73.0 || ^0.74.0 || ^0.78.0 || ^0.81.0" + }, + "peerDependenciesMeta": { + "@office-iss/react-native-win32": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "react-native-macos": { + "optional": true + }, + "react-native-windows": { + "optional": true + } + }, + "codegenConfig": { + "name": "FRNNativeCoreSpec", + "type": "all", + "jsSrcsDir": "src/specs", + "ios": { + "componentProvider": { + "Callout": "RCTCalloutComponentView", + "FocusZone": "RCTFocusZoneComponentView" + } + }, + "windows": { + "generators": [ + "componentsWindows", + "modulesWindows" + ], + "namespace": "FRNNativeCoreCodegen", + "outputDirectory": "windows/NativeCore/codegen", + "separateDataTypes": true + } + }, + "furn": { + "jestPlatform": "win32" + }, + "react-native-windows": { + "init-windows": { + "name": "FRNNativeCore", + "namespace": "FRNNativeCore", + "template": "cpp-lib" + } }, "rnx-kit": { "kitType": "library", + "alignDeps": { + "capabilities": [ + "babel-preset-react-native", + "core", + "core-android", + "core-ios", + "core-macos", + "core-windows", + "react", + "react-test-renderer" + ] + }, "extends": "@fluentui-react-native/scripts/kit-config" } } diff --git a/packages/native/Callout/react-native.config.cjs b/packages/agentic/native-core/react-native.config.cjs similarity index 78% rename from packages/native/Callout/react-native.config.cjs rename to packages/agentic/native-core/react-native.config.cjs index 5046885ab4..d495c666a0 100644 --- a/packages/native/Callout/react-native.config.cjs +++ b/packages/agentic/native-core/react-native.config.cjs @@ -5,7 +5,7 @@ module.exports = { sourceDir: 'windows', projects: [ { - projectFile: 'Callout/Callout.vcxproj', + projectFile: 'NativeCore/NativeCore.vcxproj', directDependency: true, }, ], diff --git a/packages/native/Callout/src/Callout.stories.tsx b/packages/agentic/native-core/src/components/callout/Callout.stories.tsx similarity index 100% rename from packages/native/Callout/src/Callout.stories.tsx rename to packages/agentic/native-core/src/components/callout/Callout.stories.tsx diff --git a/packages/native/Callout/src/Callout.tsx b/packages/agentic/native-core/src/components/callout/Callout.tsx similarity index 97% rename from packages/native/Callout/src/Callout.tsx rename to packages/agentic/native-core/src/components/callout/Callout.tsx index 6d0a9e33e3..b9fdd5da92 100644 --- a/packages/native/Callout/src/Callout.tsx +++ b/packages/agentic/native-core/src/components/callout/Callout.tsx @@ -6,7 +6,7 @@ import { directComponent, mergeProps, phasedComponent } from '@fluentui-react-na import type { CalloutProps } from './Callout.types'; import { calloutName } from './Callout.types'; -import NativeCalloutView, { Commands } from './CalloutNativeComponent'; +import NativeCalloutView, { Commands } from '../../specs/components/CalloutNativeComponent'; const colorTransparent = '#00000000'; diff --git a/packages/native/Callout/src/Callout.types.ts b/packages/agentic/native-core/src/components/callout/Callout.types.ts similarity index 100% rename from packages/native/Callout/src/Callout.types.ts rename to packages/agentic/native-core/src/components/callout/Callout.types.ts diff --git a/packages/native/Callout/SPEC.md b/packages/agentic/native-core/src/components/callout/SPEC.md similarity index 77% rename from packages/native/Callout/SPEC.md rename to packages/agentic/native-core/src/components/callout/SPEC.md index 92fd3b3497..e57ccfeac8 100644 --- a/packages/native/Callout/SPEC.md +++ b/packages/agentic/native-core/src/components/callout/SPEC.md @@ -4,8 +4,8 @@ Callout is an unstyled native primitive that presents children in transient UI positioned relative to a target ref, registered native anchor, or anchor -rectangle. It remains a standalone package because it owns native code and -CocoaPods integration. +rectangle. Its JS wrapper, native adapters, and codegen schema are owned by +`@fluentui-react-native/native-core`; the old Callout package is a JS-only shim. ## Contract @@ -27,8 +27,8 @@ CocoaPods integration. - macOS presents children in a native popup window and supports window focus commands through both Paper and Fabric component registrations. -- Windows uses the platform's built-in Paper `RCTCallout` and supplies a - package-owned Fabric registration for React Native Windows 0.81 and newer. +- Windows uses native-core's Fabric registration for React Native Windows + 0.81 and newer. Native-core supplies no Windows Paper implementation. - Win32 supplies the platform `RCTCallout` implementation and supports native dismissal, pointer capture, beak, and focus-restoration behavior. - Unsupported native behavior remains platform-defined rather than being @@ -39,6 +39,10 @@ CocoaPods integration. `ICalloutProps`, `ICalloutTokens`, and `CalloutNativeCommands` remain as deprecated aliases for the modern public types. +Existing `Callout`/`RCTCallout` native registration names remain unchanged. +Native applications must directly depend on `@fluentui-react-native/native-core` +so native tooling discovers the shared pod and Windows project. + ## Demonstration Interactive scenarios live in diff --git a/packages/native/Callout/src/__tests__/Callout.test.tsx b/packages/agentic/native-core/src/components/callout/__tests__/Callout.test.tsx similarity index 98% rename from packages/native/Callout/src/__tests__/Callout.test.tsx rename to packages/agentic/native-core/src/components/callout/__tests__/Callout.test.tsx index 959a94e4fc..bd10a9a60f 100644 --- a/packages/native/Callout/src/__tests__/Callout.test.tsx +++ b/packages/agentic/native-core/src/components/callout/__tests__/Callout.test.tsx @@ -8,7 +8,7 @@ import type { SlotProp } from '@fluentui-react-native/framework-base'; import { Callout } from '../Callout'; import type { CalloutHandle } from '../Callout.types'; -import { Commands } from '../CalloutNativeComponent'; +import { Commands } from '../../../specs/components/CalloutNativeComponent'; jest.mock('react-native/Libraries/ReactNative/RendererProxy', () => ({ ...jest.requireActual('react-native/Libraries/ReactNative/RendererProxy'), diff --git a/packages/native/Callout/src/__tests__/Callout.types.test.ts b/packages/agentic/native-core/src/components/callout/__tests__/Callout.types.test.ts similarity index 100% rename from packages/native/Callout/src/__tests__/Callout.types.test.ts rename to packages/agentic/native-core/src/components/callout/__tests__/Callout.types.test.ts diff --git a/packages/native/Callout/src/__tests__/__snapshots__/Callout.test.tsx.snap b/packages/agentic/native-core/src/components/callout/__tests__/__snapshots__/Callout.test.tsx.snap similarity index 100% rename from packages/native/Callout/src/__tests__/__snapshots__/Callout.test.tsx.snap rename to packages/agentic/native-core/src/components/callout/__tests__/__snapshots__/Callout.test.tsx.snap diff --git a/packages/components/FocusZone/src/FocusZone.tsx b/packages/agentic/native-core/src/components/focus-zone/FocusZone.tsx similarity index 96% rename from packages/components/FocusZone/src/FocusZone.tsx rename to packages/agentic/native-core/src/components/focus-zone/FocusZone.tsx index 7624ee2f2b..0430f6c112 100644 --- a/packages/components/FocusZone/src/FocusZone.tsx +++ b/packages/agentic/native-core/src/components/focus-zone/FocusZone.tsx @@ -7,7 +7,7 @@ import { useViewCommandFocus } from '@fluentui-react-native/interactive-hooks'; import type { FocusZoneProps } from './FocusZone.types'; import { focusZoneName } from './FocusZone.types'; -import NativeFocusZone from './FocusZoneNativeComponent'; +import NativeFocusZone from '../../specs/components/FocusZoneNativeComponent'; /** * Renders the native FocusZone without applying theme or appearance defaults. diff --git a/packages/components/FocusZone/src/FocusZone.types.ts b/packages/agentic/native-core/src/components/focus-zone/FocusZone.types.ts similarity index 100% rename from packages/components/FocusZone/src/FocusZone.types.ts rename to packages/agentic/native-core/src/components/focus-zone/FocusZone.types.ts diff --git a/packages/components/FocusZone/SPEC.md b/packages/agentic/native-core/src/components/focus-zone/SPEC.md similarity index 83% rename from packages/components/FocusZone/SPEC.md rename to packages/agentic/native-core/src/components/focus-zone/SPEC.md index 54ce2640a9..5379e8851c 100644 --- a/packages/components/FocusZone/SPEC.md +++ b/packages/agentic/native-core/src/components/focus-zone/SPEC.md @@ -3,8 +3,9 @@ ## Purpose FocusZone is an unstyled native primitive that coordinates directional and Tab -keyboard navigation among focusable descendants. It remains a standalone package -because it owns native macOS code and CocoaPods integration. +keyboard navigation among focusable descendants. Its JS wrapper, native +adapters, and codegen schema are owned by `@fluentui-react-native/native-core`; +the old FocusZone package is a JS-only shim. ## Contract @@ -45,6 +46,12 @@ because it owns native macOS code and CocoaPods integration. `FocusZoneRenderData`, and `FocusZoneType` remain as deprecated compatibility types. +Existing `FocusZone`/`RCTFocusZone` native registration names remain unchanged. +The old package's `NativeProps` export aliases native-core's +`FocusZoneNativeProps`. Native applications must directly depend on +`@fluentui-react-native/native-core` so native tooling discovers the shared pod +and Windows project. + ## Demonstration Interactive directional, circular, Tab, disabled, and default-focus scenarios diff --git a/packages/components/FocusZone/src/__tests__/FocusZone.test.tsx b/packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.test.tsx similarity index 100% rename from packages/components/FocusZone/src/__tests__/FocusZone.test.tsx rename to packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.test.tsx diff --git a/packages/components/FocusZone/src/__tests__/FocusZone.types.test.ts b/packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.types.test.ts similarity index 100% rename from packages/components/FocusZone/src/__tests__/FocusZone.types.test.ts rename to packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.types.test.ts diff --git a/packages/agentic/native-core/src/index.ts b/packages/agentic/native-core/src/index.ts index cb0ff5c3b5..a576fa7f8d 100644 --- a/packages/agentic/native-core/src/index.ts +++ b/packages/agentic/native-core/src/index.ts @@ -1 +1,27 @@ -export {}; +export { Callout } from './components/callout/Callout'; +export { calloutName } from './components/callout/Callout.types'; +export type { + CalloutHandle, + CalloutNativeCommands, + CalloutProps, + CalloutTokens, + DirectionalHint, + DismissBehaviors, + ICalloutProps, + ICalloutTokens, + RestoreFocusEvent, +} from './components/callout/Callout.types'; +export { FocusZone } from './components/focus-zone/FocusZone'; +export { focusZoneName } from './components/focus-zone/FocusZone.types'; +export type { + FocusZoneDirection, + FocusZoneProps, + FocusZoneRenderData, + FocusZoneSlotProps, + FocusZoneState, + FocusZoneTabNavigation, + FocusZoneTokens, + FocusZoneType, + NativeProps as FocusZoneNativeProps, + NavigateAtEnd, +} from './components/focus-zone/FocusZone.types'; diff --git a/packages/native/Callout/src/CalloutNativeComponent.ts b/packages/agentic/native-core/src/specs/components/CalloutNativeComponent.ts similarity index 100% rename from packages/native/Callout/src/CalloutNativeComponent.ts rename to packages/agentic/native-core/src/specs/components/CalloutNativeComponent.ts diff --git a/packages/components/FocusZone/src/FocusZoneNativeComponent.ts b/packages/agentic/native-core/src/specs/components/FocusZoneNativeComponent.ts similarity index 100% rename from packages/components/FocusZone/src/FocusZoneNativeComponent.ts rename to packages/agentic/native-core/src/specs/components/FocusZoneNativeComponent.ts diff --git a/packages/components/FocusZone/src/FocusZoneNativeComponent.win32.ts b/packages/agentic/native-core/src/specs/components/FocusZoneNativeComponent.win32.ts similarity index 100% rename from packages/components/FocusZone/src/FocusZoneNativeComponent.win32.ts rename to packages/agentic/native-core/src/specs/components/FocusZoneNativeComponent.win32.ts diff --git a/packages/agentic/native-core/tests/native-ownership.test.mjs b/packages/agentic/native-core/tests/native-ownership.test.mjs new file mode 100644 index 0000000000..bb24deee3d --- /dev/null +++ b/packages/agentic/native-core/tests/native-ownership.test.mjs @@ -0,0 +1,63 @@ +import assert from 'node:assert/strict'; +import { readFile, readdir } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import test from 'node:test'; + +const packageRoot = new URL('../', import.meta.url); +const manifest = JSON.parse(await readFile(new URL('package.json', packageRoot), 'utf8')); +const require = createRequire(import.meta.url); + +test('owns one codegen boundary for both native components and future modules', () => { + assert.equal(manifest.codegenConfig.name, 'FRNNativeCoreSpec'); + assert.equal(manifest.codegenConfig.type, 'all'); + assert.equal(manifest.codegenConfig.jsSrcsDir, 'src/specs'); + assert.notEqual(manifest.codegenConfig.includesGeneratedCode, true); + assert.deepEqual(manifest.codegenConfig.ios.componentProvider, { + Callout: 'RCTCalloutComponentView', + FocusZone: 'RCTFocusZoneComponentView', + }); + assert.deepEqual(manifest.codegenConfig.windows.generators, ['componentsWindows', 'modulesWindows']); +}); + +test('autolinks one Fabric-only Windows library registering both components', async () => { + const config = require('../react-native.config.cjs'); + assert.deepEqual(config.dependency.platforms.windows.projects, [ + { projectFile: 'NativeCore/NativeCore.vcxproj', directDependency: true }, + ]); + + const project = await readFile(new URL('windows/NativeCore/NativeCore.vcxproj', packageRoot), 'utf8'); + assert.match(project, /true<\/RnwNewArchOnly>/); + assert.match(project, /components\\Callout\\Callout\.cpp/); + assert.match(project, /components\\FocusZone\\FocusZoneComponentView\.cpp/); + const provider = await readFile(new URL('windows/NativeCore/ReactPackageProvider.cpp', packageRoot), 'utf8'); + assert.match(provider, /RegisterCalloutComponentView\(packageBuilder\)/); + assert.match(provider, /RegisterFocusZoneComponentView\(packageBuilder\)/); +}); + +test('the shared macOS pod includes both components and retains both renderer adapters', async () => { + const podspec = await readFile(new URL('FRNNativeCore.podspec', packageRoot), 'utf8'); + assert.match(podspec, /s\.name\s*=\s*'FRNNativeCore'/); + assert.match(podspec, /macos\/\*\*\/\*\.\{swift,h,m,mm\}/); + + for (const component of ['Callout', 'FocusZone']) { + const fabric = await readFile(new URL(`macos/components/${component}/fabric/RCT${component}ComponentView.mm`, packageRoot), 'utf8'); + assert.match(fabric, /react\/renderer\/components\/FRNNativeCoreSpec\/Props\.h/); + assert.ok((await readdir(new URL(`macos/components/${component}/paper/`, packageRoot))).length > 0); + assert.ok((await readdir(new URL(`macos/components/${component}/shared/`, packageRoot))).length > 0); + } +}); + +for (const shim of ['callout', 'focus-zone']) { + test(`${shim} is a JS-only compatibility shim with no duplicate native ownership`, async () => { + const root = new URL(`../../shim/${shim}/`, packageRoot); + const shimManifest = JSON.parse(await readFile(new URL('package.json', root), 'utf8')); + assert.equal(shimManifest.dependencies[manifest.name], 'workspace:*'); + assert.equal(shimManifest.codegenConfig, undefined); + assert.equal(shimManifest['react-native-windows'], undefined); + const files = await readdir(root); + assert.ok(!files.some((file) => file.endsWith('.podspec') || ['macos', 'windows', 'react-native.config.cjs'].includes(file))); + const entrypoint = await readFile(new URL('src/index.ts', root), 'utf8'); + assert.match(entrypoint, /from '@fluentui-react-native\/native-core'/); + assert.doesNotMatch(entrypoint, /export \*/); + }); +} diff --git a/packages/agentic/native-core/tsconfig.json b/packages/agentic/native-core/tsconfig.json index d952200ef0..bd2b34cb96 100644 --- a/packages/agentic/native-core/tsconfig.json +++ b/packages/agentic/native-core/tsconfig.json @@ -9,6 +9,12 @@ "include": ["src"], "exclude": ["**/*.stories.ts", "**/*.stories.tsx", "**/*.wdio.ts"], "references": [ + { + "path": "../../framework-base/tsconfig.json" + }, + { + "path": "../../utils/interactive-hooks/tsconfig.json" + }, { "path": "../../../scripts/tsconfig.json" } diff --git a/packages/components/FocusZone/windows/.gitignore b/packages/agentic/native-core/windows/.gitignore similarity index 100% rename from packages/components/FocusZone/windows/.gitignore rename to packages/agentic/native-core/windows/.gitignore diff --git a/packages/components/FocusZone/windows/ExperimentalFeatures.props b/packages/agentic/native-core/windows/ExperimentalFeatures.props similarity index 100% rename from packages/components/FocusZone/windows/ExperimentalFeatures.props rename to packages/agentic/native-core/windows/ExperimentalFeatures.props diff --git a/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.def b/packages/agentic/native-core/windows/NativeCore/NativeCore.def similarity index 100% rename from packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.def rename to packages/agentic/native-core/windows/NativeCore/NativeCore.def diff --git a/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj b/packages/agentic/native-core/windows/NativeCore/NativeCore.vcxproj similarity index 94% rename from packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj rename to packages/agentic/native-core/windows/NativeCore/NativeCore.vcxproj index 3d23cae505..ac701265e9 100644 --- a/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj +++ b/packages/agentic/native-core/windows/NativeCore/NativeCore.vcxproj @@ -6,9 +6,9 @@ true true {85648B33-7A31-434B-ACE5-6E4F6E52EBAD} - FRNFocusZone + FRNNativeCore Win32Proj - FRNFocusZone + FRNNativeCore 10.0.22621.0 en-US @@ -92,7 +92,7 @@ user32.lib;windowsapp.lib;%(AdditionalDependencies) Console true - FRNFocusZone.def + NativeCore.def @@ -107,16 +107,17 @@ - + + ReactPackageProvider.idl - - + + Create @@ -128,9 +129,6 @@ - - - diff --git a/packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.cpp b/packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.cpp similarity index 59% rename from packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.cpp rename to packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.cpp index ce6933d568..c215bf44f2 100644 --- a/packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.cpp +++ b/packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.cpp @@ -5,20 +5,23 @@ #include "ReactPackageProvider.g.cpp" #endif -#include "FocusZoneComponentView.h" +#include "components/Callout/Callout.h" +#include "components/FocusZone/FocusZoneComponentView.h" using namespace winrt::Microsoft::ReactNative; -namespace winrt::FRNFocusZone::implementation +namespace winrt::FRNNativeCore::implementation { void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept { #ifdef RNW_NEW_ARCH + AddAttributedModules(packageBuilder, true); + RegisterCalloutComponentView(packageBuilder); RegisterFocusZoneComponentView(packageBuilder); #else UNREFERENCED_PARAMETER(packageBuilder); #endif } -} // namespace winrt::FRNFocusZone::implementation +} // namespace winrt::FRNNativeCore::implementation diff --git a/packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.h b/packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.h similarity index 65% rename from packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.h rename to packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.h index 1912fd12d3..5d81282ff7 100644 --- a/packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.h +++ b/packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.h @@ -4,7 +4,7 @@ using namespace winrt::Microsoft::ReactNative; -namespace winrt::FRNFocusZone::implementation +namespace winrt::FRNNativeCore::implementation { struct ReactPackageProvider : ReactPackageProviderT @@ -14,11 +14,11 @@ struct ReactPackageProvider : ReactPackageProviderT void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept; }; -} // namespace winrt::FRNFocusZone::implementation +} // namespace winrt::FRNNativeCore::implementation -namespace winrt::FRNFocusZone::factory_implementation +namespace winrt::FRNNativeCore::factory_implementation { struct ReactPackageProvider : ReactPackageProviderT {}; -} // namespace winrt::FRNFocusZone::factory_implementation +} // namespace winrt::FRNNativeCore::factory_implementation diff --git a/packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.idl b/packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.idl similarity index 87% rename from packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.idl rename to packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.idl index f8a01091d5..7850c2224c 100644 --- a/packages/components/FocusZone/windows/FRNFocusZone/ReactPackageProvider.idl +++ b/packages/agentic/native-core/windows/NativeCore/ReactPackageProvider.idl @@ -1,4 +1,4 @@ -namespace FRNFocusZone +namespace FRNNativeCore { [webhosthidden] [default_interface] diff --git a/packages/components/FocusZone/windows/FRNFocusZone/codegen/.clang-format b/packages/agentic/native-core/windows/NativeCore/codegen/.clang-format similarity index 50% rename from packages/components/FocusZone/windows/FRNFocusZone/codegen/.clang-format rename to packages/agentic/native-core/windows/NativeCore/codegen/.clang-format index 9d159247d5..a43d914ec3 100644 --- a/packages/components/FocusZone/windows/FRNFocusZone/codegen/.clang-format +++ b/packages/agentic/native-core/windows/NativeCore/codegen/.clang-format @@ -1,2 +1,2 @@ DisableFormat: true -SortIncludes: false +SortIncludes: false \ No newline at end of file diff --git a/packages/native/Callout/windows/Callout/codegen/react/components/FRNCalloutSpec/Callout.g.h b/packages/agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec/Callout.g.h similarity index 99% rename from packages/native/Callout/windows/Callout/codegen/react/components/FRNCalloutSpec/Callout.g.h rename to packages/agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec/Callout.g.h index ef6731db34..072434e2c0 100644 --- a/packages/native/Callout/windows/Callout/codegen/react/components/FRNCalloutSpec/Callout.g.h +++ b/packages/agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec/Callout.g.h @@ -16,7 +16,7 @@ #ifdef RNW_NEW_ARCH -namespace winrt::FluentUI::Callout::Codegen { +namespace FRNNativeCoreCodegen { REACT_STRUCT(CalloutSpec_CalloutProps_anchorRect) struct CalloutSpec_CalloutProps_anchorRect { @@ -370,6 +370,6 @@ void RegisterCalloutNativeComponent( }); } -} // namespace winrt::FluentUI::Callout::Codegen +} // namespace FRNNativeCoreCodegen #endif // #ifdef RNW_NEW_ARCH diff --git a/packages/components/FocusZone/windows/FRNFocusZone/codegen/react/components/FRNFocusZoneSpec/FocusZone.g.h b/packages/agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec/FocusZone.g.h similarity index 99% rename from packages/components/FocusZone/windows/FRNFocusZone/codegen/react/components/FRNFocusZoneSpec/FocusZone.g.h rename to packages/agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec/FocusZone.g.h index da24d5e0cd..e6e2080614 100644 --- a/packages/components/FocusZone/windows/FRNFocusZone/codegen/react/components/FRNFocusZoneSpec/FocusZone.g.h +++ b/packages/agentic/native-core/windows/NativeCore/codegen/react/components/FRNNativeCoreSpec/FocusZone.g.h @@ -16,7 +16,7 @@ #ifdef RNW_NEW_ARCH -namespace FRNFocusZoneCodegen { +namespace FRNNativeCoreCodegen { REACT_STRUCT(FocusZoneProps) struct FocusZoneProps : winrt::implements { @@ -238,6 +238,6 @@ void RegisterFocusZoneNativeComponent( }); } -} // namespace FRNFocusZoneCodegen +} // namespace FRNNativeCoreCodegen #endif // #ifdef RNW_NEW_ARCH diff --git a/packages/native/Callout/windows/Callout/Callout.cpp b/packages/agentic/native-core/windows/NativeCore/components/Callout/Callout.cpp similarity index 100% rename from packages/native/Callout/windows/Callout/Callout.cpp rename to packages/agentic/native-core/windows/NativeCore/components/Callout/Callout.cpp diff --git a/packages/native/Callout/windows/Callout/Callout.h b/packages/agentic/native-core/windows/NativeCore/components/Callout/Callout.h similarity index 86% rename from packages/native/Callout/windows/Callout/Callout.h rename to packages/agentic/native-core/windows/NativeCore/components/Callout/Callout.h index 4a434fbfa9..41b5ffb623 100644 --- a/packages/native/Callout/windows/Callout/Callout.h +++ b/packages/agentic/native-core/windows/NativeCore/components/Callout/Callout.h @@ -6,7 +6,7 @@ #include "NativeModules.h" -#include "codegen/react/components/FRNCalloutSpec/Callout.g.h" +#include "codegen/react/components/FRNNativeCoreSpec/Callout.g.h" #include #include @@ -19,6 +19,8 @@ namespace winrt::FluentUI::Callout { +namespace Codegen = ::FRNNativeCoreCodegen; + } // namespace winrt::FluentUI::Callout void RegisterCalloutComponentView( diff --git a/packages/components/FocusZone/windows/FRNFocusZone/FocusZoneComponentView.cpp b/packages/agentic/native-core/windows/NativeCore/components/FocusZone/FocusZoneComponentView.cpp similarity index 98% rename from packages/components/FocusZone/windows/FRNFocusZone/FocusZoneComponentView.cpp rename to packages/agentic/native-core/windows/NativeCore/components/FocusZone/FocusZoneComponentView.cpp index f75854d11e..b373546a62 100644 --- a/packages/components/FocusZone/windows/FRNFocusZone/FocusZoneComponentView.cpp +++ b/packages/agentic/native-core/windows/NativeCore/components/FocusZone/FocusZoneComponentView.cpp @@ -4,7 +4,7 @@ #ifdef RNW_NEW_ARCH -#include "codegen/react/components/FRNFocusZoneSpec/FocusZone.g.h" +#include "codegen/react/components/FRNNativeCoreSpec/FocusZone.g.h" namespace winrt::FRNFocusZone { @@ -29,7 +29,7 @@ void CollectFocusableDescendants( struct FocusZoneComponentView : winrt::implements, - FRNFocusZoneCodegen::BaseFocusZone { + FRNNativeCoreCodegen::BaseFocusZone { void Initialize(const winrtRN::ComponentView &view) noexcept override { m_containerTag = view.Tag(); @@ -586,7 +586,7 @@ struct FocusZoneComponentView void RegisterFocusZoneComponentView(const winrt::Microsoft::ReactNative::IReactPackageBuilder &packageBuilder) noexcept { using ComponentView = winrt::FRNFocusZone::FocusZoneComponentView; - FRNFocusZoneCodegen::RegisterFocusZoneNativeComponent(packageBuilder, {}); + FRNNativeCoreCodegen::RegisterFocusZoneNativeComponent(packageBuilder, {}); } #endif diff --git a/packages/components/FocusZone/windows/FRNFocusZone/FocusZoneComponentView.h b/packages/agentic/native-core/windows/NativeCore/components/FocusZone/FocusZoneComponentView.h similarity index 100% rename from packages/components/FocusZone/windows/FRNFocusZone/FocusZoneComponentView.h rename to packages/agentic/native-core/windows/NativeCore/components/FocusZone/FocusZoneComponentView.h diff --git a/packages/components/FocusZone/windows/FRNFocusZone/packages.lock.json b/packages/agentic/native-core/windows/NativeCore/packages.lock.json similarity index 100% rename from packages/components/FocusZone/windows/FRNFocusZone/packages.lock.json rename to packages/agentic/native-core/windows/NativeCore/packages.lock.json diff --git a/packages/components/FocusZone/windows/FRNFocusZone/pch.cpp b/packages/agentic/native-core/windows/NativeCore/pch.cpp similarity index 100% rename from packages/components/FocusZone/windows/FRNFocusZone/pch.cpp rename to packages/agentic/native-core/windows/NativeCore/pch.cpp diff --git a/packages/components/FocusZone/windows/FRNFocusZone/pch.h b/packages/agentic/native-core/windows/NativeCore/pch.h similarity index 100% rename from packages/components/FocusZone/windows/FRNFocusZone/pch.h rename to packages/agentic/native-core/windows/NativeCore/pch.h diff --git a/packages/components/FocusZone/windows/FRNFocusZone/targetver.h b/packages/agentic/native-core/windows/NativeCore/targetver.h similarity index 100% rename from packages/components/FocusZone/windows/FRNFocusZone/targetver.h rename to packages/agentic/native-core/windows/NativeCore/targetver.h diff --git a/packages/components/FocusZone/windows/NuGet.Config b/packages/agentic/native-core/windows/NuGet.Config similarity index 100% rename from packages/components/FocusZone/windows/NuGet.Config rename to packages/agentic/native-core/windows/NuGet.Config diff --git a/packages/agentic/storybook-desktop-runtime/package.json b/packages/agentic/storybook-desktop-runtime/package.json index 51388d9ae6..0272613670 100644 --- a/packages/agentic/storybook-desktop-runtime/package.json +++ b/packages/agentic/storybook-desktop-runtime/package.json @@ -31,9 +31,9 @@ "test": "fluentui-scripts jest" }, "dependencies": { - "@fluentui-react-native/callout": "workspace:*", "@fluentui-react-native/default-theme": "workspace:*", "@fluentui-react-native/design": "workspace:*", + "@fluentui-react-native/native-core": "workspace:*", "@rnx-kit/metro-config": "catalog:", "@rnx-kit/metro-resolver-symlinks": "catalog:", "@storybook/react-native": "^10.4.7", @@ -85,7 +85,7 @@ "jestPlatform": "macos", "knip": { "ignoreDependencies": [ - "@fluentui-react-native/callout" + "@fluentui-react-native/native-core" ] } }, diff --git a/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx b/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx index 1d1e36b211..af9f3eceb7 100644 --- a/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { StyleSheet } from 'react-native'; -import { Callout } from '@fluentui-react-native/callout'; -import type { CalloutProps, DirectionalHint } from '@fluentui-react-native/callout'; +import { Callout } from '@fluentui-react-native/native-core'; +import type { CalloutProps, DirectionalHint } from '@fluentui-react-native/native-core'; import { RootInputBoundary } from '@fluentui-react-native/design'; import { useTheme } from '@storybook/react-native-theming'; diff --git a/packages/agentic/storybook-desktop-runtime/tsconfig.json b/packages/agentic/storybook-desktop-runtime/tsconfig.json index d7156beca4..2fe2c0c71f 100644 --- a/packages/agentic/storybook-desktop-runtime/tsconfig.json +++ b/packages/agentic/storybook-desktop-runtime/tsconfig.json @@ -8,15 +8,15 @@ }, "include": ["src"], "references": [ - { - "path": "../../native/Callout/tsconfig.json" - }, { "path": "../../theming/default-theme/tsconfig.json" }, { "path": "../design/tsconfig.json" }, + { + "path": "../native-core/tsconfig.json" + }, { "path": "../../../scripts/tsconfig.json" } diff --git a/packages/agentic/storybook-desktop/src/config/makeDesktopStorybookConfig.test.ts b/packages/agentic/storybook-desktop/src/config/makeDesktopStorybookConfig.test.ts index dcf4c56e28..49cead7354 100644 --- a/packages/agentic/storybook-desktop/src/config/makeDesktopStorybookConfig.test.ts +++ b/packages/agentic/storybook-desktop/src/config/makeDesktopStorybookConfig.test.ts @@ -20,7 +20,7 @@ function makeAgenticConfig() { }, }, ], - '@fluentui-react-native/callout', + '@fluentui-react-native/native-core', ], }); } @@ -40,7 +40,7 @@ describe('DesktopStorybookConfig', () => { const config = makeAgenticConfig(); const packages = config.getStoryPackages('macos'); - expect(packages.map(({ name }) => name)).toEqual(['@fluentui-react-native/components', '@fluentui-react-native/callout']); + expect(packages.map(({ name }) => name)).toEqual(['@fluentui-react-native/components', '@fluentui-react-native/native-core']); expect(packages[0].root).toBe(path.resolve(storybookRoot, '../../packages/agentic/components')); expect(packages[0].storyPatterns).toEqual(['src/**/*.stories.?(ts|tsx)']); }); @@ -50,19 +50,19 @@ describe('DesktopStorybookConfig', () => { expect(config.getStoryGlobs('macos')).toEqual([ '../../../packages/agentic/components/src/**/*.stories.?(ts|tsx)', - '../../../packages/native/Callout/src/**/*.stories.?(ts|tsx)', + '../../../packages/agentic/native-core/src/**/*.stories.?(ts|tsx)', ]); expect(config.getStoryGlobs('win32')).toEqual([ '../../../packages/agentic/components/src/primitives/**/*.stories.?(ts|tsx)', '../../../packages/agentic/components/src/components/!(accordion|list-item)/**/*.stories.?(ts|tsx)', - '../../../packages/native/Callout/src/**/*.stories.?(ts|tsx)', + '../../../packages/agentic/native-core/src/**/*.stories.?(ts|tsx)', ]); }); test('filters packages by platform and applies addon defaults', () => { const config = makeDesktopStorybookConfig({ projectRoot: storybookRoot, - storyPackages: [['@fluentui-react-native/callout', { platforms: ['macos'] }]], + storyPackages: [['@fluentui-react-native/native-core', { platforms: ['macos'] }]], }); expect(config.getStorybookConfig('windows')).toMatchObject({ diff --git a/packages/components/ContextualMenu/tsconfig.json b/packages/components/ContextualMenu/tsconfig.json index 2ab212fd85..753669edfc 100644 --- a/packages/components/ContextualMenu/tsconfig.json +++ b/packages/components/ContextualMenu/tsconfig.json @@ -12,13 +12,13 @@ "path": "../../utils/adapters/tsconfig.json" }, { - "path": "../../native/Callout/tsconfig.json" + "path": "../../shim/callout/tsconfig.json" }, { "path": "../../agentic/design/tsconfig.json" }, { - "path": "../FocusZone/tsconfig.json" + "path": "../../shim/focus-zone/tsconfig.json" }, { "path": "../../framework-base/tsconfig.json" diff --git a/packages/components/FocusZone/RCTFocusZone.podspec b/packages/components/FocusZone/RCTFocusZone.podspec deleted file mode 100644 index 13ae57174e..0000000000 --- a/packages/components/FocusZone/RCTFocusZone.podspec +++ /dev/null @@ -1,21 +0,0 @@ -require 'json' - -package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) - -Pod::Spec.new do |s| - s.name = 'RCTFocusZone' - s.version = package['version'] - s.summary = package['description'] - s.license = package['license'] - - s.authors = package['author'] - s.homepage = "https://github.com/microsoft/fluentui-react-native" - - s.source = { :git => "https://github.com/microsoft/fluentui-react-native.git", :tag => "#{s.version}" } - s.swift_version = "5" - - s.osx.deployment_target = "10.15" - s.osx.source_files = "macos/*.{swift,h,m,mm}" - - install_modules_dependencies(s) -end diff --git a/packages/components/FocusZone/react-native.config.cjs b/packages/components/FocusZone/react-native.config.cjs deleted file mode 100644 index e6858db429..0000000000 --- a/packages/components/FocusZone/react-native.config.cjs +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - dependency: { - platforms: { - windows: { - sourceDir: 'windows', - projects: [ - { - projectFile: 'FRNFocusZone/FRNFocusZone.vcxproj', - directDependency: true, - }, - ], - }, - }, - }, -}; diff --git a/packages/components/FocusZone/windows/FRNFocusZone.sln b/packages/components/FocusZone/windows/FRNFocusZone.sln deleted file mode 100644 index 08d4bc6912..0000000000 --- a/packages/components/FocusZone/windows/FRNFocusZone.sln +++ /dev/null @@ -1,43 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.3.32929.385 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FRNFocusZone", "FRNFocusZone\FRNFocusZone.vcxproj", "{85648B33-7A31-434B-ACE5-6E4F6E52EBAD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Debug|ARM64 = Debug|ARM64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - Release|ARM64 = Release|ARM64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|x64.ActiveCfg = Debug|x64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|x64.Build.0 = Debug|x64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|x64.Deploy.0 = Debug|x64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|x86.ActiveCfg = Debug|Win32 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|x86.Build.0 = Debug|Win32 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|x86.Deploy.0 = Debug|Win32 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|ARM64.Build.0 = Debug|ARM64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Debug|ARM64.Deploy.0 = Debug|ARM64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|x64.ActiveCfg = Release|x64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|x64.Build.0 = Release|x64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|x64.Deploy.0 = Release|x64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|x86.ActiveCfg = Release|Win32 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|x86.Build.0 = Release|Win32 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|x86.Deploy.0 = Release|Win32 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|ARM64.ActiveCfg = Release|ARM64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|ARM64.Build.0 = Release|ARM64 - {85648B33-7A31-434B-ACE5-6E4F6E52EBAD}.Release|ARM64.Deploy.0 = Release|ARM64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {CA064327-BA5B-4132-B77B-23C9DDDF9E92} - EndGlobalSection -EndGlobal diff --git a/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.rc b/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.rc deleted file mode 100644 index 3212c105fce3ed3e784a1f88d04cd4b26a0d7f4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160 zcmZXNK?;LF3`O6%&^rveEI5bgx?A_6wiU#d(Ye0ubG8z~PhNhK-yVqs9!&HkKCI@G zP1ed*G99zsotqJOF|wFRzNv#OsmETn>aBy_ac$zOr{T)QFR^GXU7XIkhvKbH`wefZ G;{F4P;Ty#O diff --git a/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj.filters b/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj.filters deleted file mode 100644 index b4602ae41c..0000000000 --- a/packages/components/FocusZone/windows/FRNFocusZone/FRNFocusZone.vcxproj.filters +++ /dev/null @@ -1,44 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - - - Resource Files - - - \ No newline at end of file diff --git a/packages/components/FocusZone/windows/FRNFocusZone/resource.h b/packages/components/FocusZone/windows/FRNFocusZone/resource.h deleted file mode 100644 index fe63e7c1ad..0000000000 --- a/packages/components/FocusZone/windows/FRNFocusZone/resource.h +++ /dev/null @@ -1,5 +0,0 @@ -// -// Microsoft Visual C++ generated include file. -// Used by FRNFocusZone.rc - -#pragma once diff --git a/packages/components/Menu/tsconfig.json b/packages/components/Menu/tsconfig.json index 72d42549d5..36b2d5eb8f 100644 --- a/packages/components/Menu/tsconfig.json +++ b/packages/components/Menu/tsconfig.json @@ -15,13 +15,13 @@ "path": "../Button/tsconfig.json" }, { - "path": "../../native/Callout/tsconfig.json" + "path": "../../shim/callout/tsconfig.json" }, { "path": "../../agentic/design/tsconfig.json" }, { - "path": "../FocusZone/tsconfig.json" + "path": "../../shim/focus-zone/tsconfig.json" }, { "path": "../../framework-base/tsconfig.json" diff --git a/packages/components/RadioGroup/tsconfig.json b/packages/components/RadioGroup/tsconfig.json index 82457146a4..dbcd3d438c 100644 --- a/packages/components/RadioGroup/tsconfig.json +++ b/packages/components/RadioGroup/tsconfig.json @@ -15,7 +15,7 @@ "path": "../../agentic/design/tsconfig.json" }, { - "path": "../FocusZone/tsconfig.json" + "path": "../../shim/focus-zone/tsconfig.json" }, { "path": "../../framework-base/tsconfig.json" diff --git a/packages/components/TabList/tsconfig.json b/packages/components/TabList/tsconfig.json index 1644446a07..137360d774 100644 --- a/packages/components/TabList/tsconfig.json +++ b/packages/components/TabList/tsconfig.json @@ -15,7 +15,7 @@ "path": "../../agentic/design/tsconfig.json" }, { - "path": "../FocusZone/tsconfig.json" + "path": "../../shim/focus-zone/tsconfig.json" }, { "path": "../../framework-base/tsconfig.json" diff --git a/packages/deprecated/foundation-compose/AGENTS.md b/packages/deprecated/foundation-compose/AGENTS.md index 0ef61601ae..8a179372b2 100644 --- a/packages/deprecated/foundation-compose/AGENTS.md +++ b/packages/deprecated/foundation-compose/AGENTS.md @@ -147,7 +147,7 @@ automatically. `ref` during preparation, commonly with `useViewCommandFocus`; type ref-bearing roots with `React.PropsWithRef<...>`. For imperative native APIs, use an internal native ref plus `useImperativeHandle`, as in - `packages/native/Callout/src/Callout.tsx`. + `packages/agentic/native-core/src/components/callout/Callout.tsx`. - Do not introduce `forwardRef` or a new public `ref` convention into an established v0 API without an explicit migration requirement. diff --git a/packages/experimental/Dropdown/tsconfig.json b/packages/experimental/Dropdown/tsconfig.json index d7fb6048b8..a6dbd1a030 100644 --- a/packages/experimental/Dropdown/tsconfig.json +++ b/packages/experimental/Dropdown/tsconfig.json @@ -15,7 +15,7 @@ "path": "../../components/Button/tsconfig.json" }, { - "path": "../../native/Callout/tsconfig.json" + "path": "../../shim/callout/tsconfig.json" }, { "path": "../../agentic/design/tsconfig.json" diff --git a/packages/experimental/Tooltip/tsconfig.json b/packages/experimental/Tooltip/tsconfig.json index 011332a5de..db3204acba 100644 --- a/packages/experimental/Tooltip/tsconfig.json +++ b/packages/experimental/Tooltip/tsconfig.json @@ -12,7 +12,7 @@ "path": "../../components/Button/tsconfig.json" }, { - "path": "../../native/Callout/tsconfig.json" + "path": "../../shim/callout/tsconfig.json" }, { "path": "../../framework-base/tsconfig.json" diff --git a/packages/libraries/core/tsconfig.json b/packages/libraries/core/tsconfig.json index 5bd6e0487c..b675c0d1e4 100644 --- a/packages/libraries/core/tsconfig.json +++ b/packages/libraries/core/tsconfig.json @@ -21,7 +21,7 @@ "path": "../../components/Button/tsconfig.json" }, { - "path": "../../native/Callout/tsconfig.json" + "path": "../../shim/callout/tsconfig.json" }, { "path": "../../components/Checkbox/tsconfig.json" @@ -33,7 +33,7 @@ "path": "../../components/FocusTrapZone/tsconfig.json" }, { - "path": "../../components/FocusZone/tsconfig.json" + "path": "../../shim/focus-zone/tsconfig.json" }, { "path": "../../utils/interactive-hooks/tsconfig.json" diff --git a/packages/native/Callout/windows/.gitignore b/packages/native/Callout/windows/.gitignore deleted file mode 100644 index 0fd0acfc6d..0000000000 --- a/packages/native/Callout/windows/.gitignore +++ /dev/null @@ -1,46 +0,0 @@ -*AppPackages* -*BundleArtifacts* - -#OS junk files -[Tt]humbs.db -*.DS_Store - -#Visual Studio files -*.[Oo]bj -*.user -*.aps -*.pch -*.vspscc -*.vssscc -*_i.c -*_p.c -*.ncb -*.suo -*.tlb -*.tlh -*.bak -*.[Cc]ache -*.ilk -*.log -*.lib -*.sbr -*.sdf -*.opensdf -*.opendb -*.unsuccessfulbuild -ipch/ -[Oo]bj/ -[Bb]in -[Dd]ebug*/ -[Rr]elease*/ -Ankh.NoLoad -.vs/ -# Visual C++ cache files - -#Files generated by the VS build -**/Generated Files/** - -#Files generated by MS build -*.binlog -*.err -*.wrn diff --git a/packages/native/Callout/windows/Callout/Callout.def b/packages/native/Callout/windows/Callout/Callout.def deleted file mode 100644 index 24e7c1235c..0000000000 --- a/packages/native/Callout/windows/Callout/Callout.def +++ /dev/null @@ -1,3 +0,0 @@ -EXPORTS -DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE -DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/packages/native/Callout/windows/Callout/Callout.vcxproj b/packages/native/Callout/windows/Callout/Callout.vcxproj deleted file mode 100644 index 88efc1ff9b..0000000000 --- a/packages/native/Callout/windows/Callout/Callout.vcxproj +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - true - true - true - {FE36524A-FE8C-456A-9368-08FB1EB16CF8} - FluentUICallout - FluentUI.Callout - en-US - 16.0 - false - Windows Store - 10.0 - 10.0.19041.0 - 10.0.17763.0 - - - $([MSBuild]::GetDirectoryNameOfFileAbove($(SolutionDir), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ - true - - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Debug - x64 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Release - x64 - - - - DynamicLibrary - Unicode - false - - - true - true - - - false - true - false - - - - - - - - - - - - - - Use - pch.h - $(IntDir)pch.pch - Level4 - %(AdditionalOptions) /bigobj - 4453;28204 - _WINRT_DLL;%(PreprocessorDefinitions) - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - - - User32.lib;%(AdditionalDependencies) - Console - true - Callout.def - - - - - _DEBUG;%(PreprocessorDefinitions) - - - - - NDEBUG;%(PreprocessorDefinitions) - - - - - false - - - - - - ReactPackageProvider.idl - - - - - - - Create - - - ReactPackageProvider.idl - - - - - - - - - - - - - - - - - This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}. - - - - - diff --git a/packages/native/Callout/windows/Callout/ReactPackageProvider.cpp b/packages/native/Callout/windows/Callout/ReactPackageProvider.cpp deleted file mode 100644 index bac1881140..0000000000 --- a/packages/native/Callout/windows/Callout/ReactPackageProvider.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" - -#include "ReactPackageProvider.h" -#if __has_include("ReactPackageProvider.g.cpp") -#include "ReactPackageProvider.g.cpp" -#endif - -#include "Callout.h" - -using namespace winrt::Microsoft::ReactNative; - -namespace winrt::FluentUI::Callout::implementation { - -void ReactPackageProvider::CreatePackage( - IReactPackageBuilder const &packageBuilder) noexcept { - AddAttributedModules(packageBuilder, true); - -#ifdef RNW_NEW_ARCH - RegisterCalloutComponentView(packageBuilder); -#endif // #ifdef RNW_NEW_ARCH -} - -} // namespace winrt::FluentUI::Callout::implementation diff --git a/packages/native/Callout/windows/Callout/ReactPackageProvider.h b/packages/native/Callout/windows/Callout/ReactPackageProvider.h deleted file mode 100644 index ee4a609103..0000000000 --- a/packages/native/Callout/windows/Callout/ReactPackageProvider.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once - -#include "ReactPackageProvider.g.h" - -using namespace winrt::Microsoft::ReactNative; - -namespace winrt::FluentUI::Callout::implementation { - -struct ReactPackageProvider : ReactPackageProviderT { - ReactPackageProvider() = default; - - void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept; -}; - -} // namespace winrt::FluentUI::Callout::implementation - -namespace winrt::FluentUI::Callout::factory_implementation { - -struct ReactPackageProvider - : ReactPackageProviderT {}; - -} // namespace winrt::FluentUI::Callout::factory_implementation diff --git a/packages/native/Callout/windows/Callout/ReactPackageProvider.idl b/packages/native/Callout/windows/Callout/ReactPackageProvider.idl deleted file mode 100644 index cd726b6e61..0000000000 --- a/packages/native/Callout/windows/Callout/ReactPackageProvider.idl +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace FluentUI.Callout -{ - [webhosthidden] - [default_interface] - runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider - { - ReactPackageProvider(); - }; -} diff --git a/packages/native/Callout/windows/Callout/codegen/.clang-format b/packages/native/Callout/windows/Callout/codegen/.clang-format deleted file mode 100644 index 9d159247d5..0000000000 --- a/packages/native/Callout/windows/Callout/codegen/.clang-format +++ /dev/null @@ -1,2 +0,0 @@ -DisableFormat: true -SortIncludes: false diff --git a/packages/native/Callout/windows/Callout/packages.lock.json b/packages/native/Callout/windows/Callout/packages.lock.json deleted file mode 100644 index 396b4e4c7a..0000000000 --- a/packages/native/Callout/windows/Callout/packages.lock.json +++ /dev/null @@ -1,151 +0,0 @@ -{ - "version": 1, - "dependencies": { - "native,Version=v0.0": { - "boost": { - "type": "Direct", - "requested": "[1.84.0, )", - "resolved": "1.84.0", - "contentHash": "4el2YP3cNJDVFPdzOso+LxGvdWP2rHxML4siq8VdonNypW2m4q503tHfCj6vK0L1UfxioE2hpFGb4ITEua73tg==" - }, - "Microsoft.ReactNative": { - "type": "Direct", - "requested": "[0.81.35, )", - "resolved": "0.81.35", - "contentHash": "WjsJFALaLLUvJHUBw8k8G8/PB3p5qvqqXG7NYJefHOgqB7MbCSOnD/bckIqKcp53J+MkPxqaeg5tnYLVTVhqwQ==" - }, - "Microsoft.ReactNative.Cxx": { - "type": "Direct", - "requested": "[0.81.35, )", - "resolved": "0.81.35", - "contentHash": "oadpIMSLN11M9W/hyZKyiCKE2wMvjb80Bl5jInVUmqDJWNswxnu7W5Kt/NA9ciy+BN0ru62ucO0E2PJDrnP/Jg==", - "dependencies": { - "Microsoft.ReactNative": "0.81.35" - } - }, - "Microsoft.VCRTForwarders.140": { - "type": "Direct", - "requested": "[1.0.2-rc, )", - "resolved": "1.0.2-rc", - "contentHash": "/r+sjtEeCIGyDhobIZ5hSmYhC/dSyGZxf1SxYJpElUhB0LMCktOMFs9gXrauXypIFECpVynNyVjAmJt6hjJ5oQ==" - }, - "Microsoft.Windows.CppWinRT": { - "type": "Direct", - "requested": "[2.0.230706.1, )", - "resolved": "2.0.230706.1", - "contentHash": "l0D7oCw/5X+xIKHqZTi62TtV+1qeSz7KVluNFdrJ9hXsst4ghvqQ/Yhura7JqRdZWBXAuDS0G0KwALptdoxweQ==" - }, - "Microsoft.WindowsAppSDK": { - "type": "Direct", - "requested": "[1.8.260508005, )", - "resolved": "1.8.260508005", - "contentHash": "+aA+zrvqJKgsn/1TPOSR0Uy7dkMO5jI/+cDWPu2pWmXe4KQxYkR8gQFY9IrfbgCxxSd/yl1zMcAKD/4HBbNqaw==", - "dependencies": { - "Microsoft.WindowsAppSDK.AI": "[1.8.76]", - "Microsoft.WindowsAppSDK.Base": "[1.8.251216001]", - "Microsoft.WindowsAppSDK.DWrite": "[1.8.25122902]", - "Microsoft.WindowsAppSDK.Foundation": "[1.8.260505001]", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "[1.8.260430001]", - "Microsoft.WindowsAppSDK.ML": "[1.8.2197]", - "Microsoft.WindowsAppSDK.Runtime": "[1.8.260508005]", - "Microsoft.WindowsAppSDK.Widgets": "[1.8.251231004]", - "Microsoft.WindowsAppSDK.WinUI": "[1.8.260505002]" - } - }, - "Microsoft.Web.WebView2": { - "type": "Transitive", - "resolved": "1.0.3179.45", - "contentHash": "3pokSH5CnN0G6rGhGFo1y87inxYhNxBQ2Vdf0wlvBj99KHxQJormjDACmqRnFeUsmuNFIhWwfAL1ztq7wD5qRA==" - }, - "Microsoft.Windows.SDK.BuildTools": { - "type": "Transitive", - "resolved": "10.0.26100.4654", - "contentHash": "2mgcOlj/t2RfSyyw+pVESfO+Tk1RkfQzto9Vrq42M1lUQIfQEwbi8QLha9GXWIOj+TFzeHIEJckIoF25mgiM8A==" - }, - "Microsoft.Windows.SDK.BuildTools.MSIX": { - "type": "Transitive", - "resolved": "1.7.20250829.1", - "contentHash": "IMdvRmCIZnBS5GkYnv0po1bcx6U1OF39pqA4TphQ9evDzpCRoSE19/PkDvlUNNrBavTsLIEJgd/TAIFner75ow==" - }, - "Microsoft.WindowsAppSDK.AI": { - "type": "Transitive", - "resolved": "1.8.76", - "contentHash": "Ayn9QybcwzH+c8eQlE7dm2oO3Jrcn2uohLcsHJpCbLOAfcisjzwtSBe0oyulbaJ86R4eDSX3RDS25tsjGpIqyQ==", - "dependencies": { - "Microsoft.WindowsAppSDK.Base": "1.8.251216001", - "Microsoft.WindowsAppSDK.Foundation": "1.8.260501000" - } - }, - "Microsoft.WindowsAppSDK.Base": { - "type": "Transitive", - "resolved": "1.8.251216001", - "contentHash": "PS1wriuFknz3W2F2P/e6RvOTM35w89Lsj/f0QmUEPrJjKnc+jM0JLX1vfdytI14y1gNRUTm9uclwP0aH/SVU5w==", - "dependencies": { - "Microsoft.Windows.SDK.BuildTools": "10.0.26100.4654", - "Microsoft.Windows.SDK.BuildTools.MSIX": "1.7.20250829.1" - } - }, - "Microsoft.WindowsAppSDK.DWrite": { - "type": "Transitive", - "resolved": "1.8.25122902", - "contentHash": "zFNn07i7Cyz62Y8FnPQAyzeZK7ww3m9t42i9pzy4C04pNbyUDQ4fG7pB6VSh6n4EyFuYtuFQuDzt4mKmXFrkrg==", - "dependencies": { - "Microsoft.WindowsAppSDK.Base": "1.8.251216001" - } - }, - "Microsoft.WindowsAppSDK.Foundation": { - "type": "Transitive", - "resolved": "1.8.260505001", - "contentHash": "41SSoEn3sKKCAVPA/w18zVJwV1C7aDEkPS2f6Zyp19m27tDEmteEp0XS3Ln3b0ElYR4FfPEPvIDbJPSA9vePGw==", - "dependencies": { - "Microsoft.WindowsAppSDK.Base": "1.8.251216001", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "1.8.260430001" - } - }, - "Microsoft.WindowsAppSDK.InteractiveExperiences": { - "type": "Transitive", - "resolved": "1.8.260430001", - "contentHash": "fTPCnQb3ZarMh9khlEfbLDllcZzK0tSP+2S6W/T4cPyLLSAmARm8Gd3AC5kqubnDjzTvG+1lNZ1bZGFsIHplJQ==", - "dependencies": { - "Microsoft.WindowsAppSDK.Base": "1.8.251216001" - } - }, - "Microsoft.WindowsAppSDK.ML": { - "type": "Transitive", - "resolved": "1.8.2197", - "contentHash": "6Bc1SOLd5HicY3GbF+zr76YBfH4iZOKeEGxTK/lHKAK2ExZTWavOADxB2CKSi/irF4dWSngUdRFopWPmckJ6fA==", - "dependencies": { - "Microsoft.WindowsAppSDK.Base": "1.8.251216001", - "Microsoft.WindowsAppSDK.Foundation": "1.8.260505001" - } - }, - "Microsoft.WindowsAppSDK.Runtime": { - "type": "Transitive", - "resolved": "1.8.260508005", - "contentHash": "2JqXzA4heHSkkaXJNyEvYtpv2wsEUMhwQzgXmZsFmYSkUXSdeVc6hdHcWoBK1SY9l1Sjd1brLt7h16kIpgh2kA==", - "dependencies": { - "Microsoft.WindowsAppSDK.Base": "1.8.251216001" - } - }, - "Microsoft.WindowsAppSDK.Widgets": { - "type": "Transitive", - "resolved": "1.8.251231004", - "contentHash": "bIWqQYR8DCoB1SoPOMil5AtgtkTn438wJTdpsHgyO/6o7Eh7PMP5BzrR0KbDsFqy+4LhPWQ4vtwko5k93fECcA==", - "dependencies": { - "Microsoft.WindowsAppSDK.Base": "1.8.251216001" - } - }, - "Microsoft.WindowsAppSDK.WinUI": { - "type": "Transitive", - "resolved": "1.8.260505002", - "contentHash": "/hGl6EOmo8aeJR2bYbOmGhOicnJK4EY+u+cQI+jm8H1uXThfMX32DsfKOt9LkOcu8AKX3j5FpiBay8ObUSytIw==", - "dependencies": { - "Microsoft.Web.WebView2": "1.0.3179.45", - "Microsoft.WindowsAppSDK.Base": "1.8.251216001", - "Microsoft.WindowsAppSDK.Foundation": "1.8.260505001", - "Microsoft.WindowsAppSDK.InteractiveExperiences": "1.8.260430001" - } - } - } - } -} diff --git a/packages/native/Callout/windows/Callout/pch.cpp b/packages/native/Callout/windows/Callout/pch.cpp deleted file mode 100644 index bcb5590be1..0000000000 --- a/packages/native/Callout/windows/Callout/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" diff --git a/packages/native/Callout/windows/Callout/pch.h b/packages/native/Callout/windows/Callout/pch.h deleted file mode 100644 index 4eac9041ed..0000000000 --- a/packages/native/Callout/windows/Callout/pch.h +++ /dev/null @@ -1,28 +0,0 @@ -// pch.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#pragma once - -#define NOMINMAX 1 -//#define WIN32_LEAN_AND_MEAN 1 -//#define WINRT_LEAN_AND_MEAN 1 - -// Windows Header Files -#include -#undef GetCurrentTime -#include - -// WinRT Header Files -#include -#include -#include - -// C RunTime Header Files -#include -#include -#include -#include - -// Reference additional headers your project requires here diff --git a/packages/native/Callout/windows/ExperimentalFeatures.props b/packages/native/Callout/windows/ExperimentalFeatures.props deleted file mode 100644 index db10c59f9a..0000000000 --- a/packages/native/Callout/windows/ExperimentalFeatures.props +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - true - - - true - - true - - - diff --git a/packages/native/Callout/windows/NuGet.Config b/packages/native/Callout/windows/NuGet.Config deleted file mode 100644 index aee3137fd7..0000000000 --- a/packages/native/Callout/windows/NuGet.Config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/packages/native/Callout/CHANGELOG.json b/packages/shim/callout/CHANGELOG.json similarity index 100% rename from packages/native/Callout/CHANGELOG.json rename to packages/shim/callout/CHANGELOG.json diff --git a/packages/native/Callout/CHANGELOG.md b/packages/shim/callout/CHANGELOG.md similarity index 100% rename from packages/native/Callout/CHANGELOG.md rename to packages/shim/callout/CHANGELOG.md diff --git a/packages/shim/callout/README.md b/packages/shim/callout/README.md new file mode 100644 index 0000000000..af29596036 --- /dev/null +++ b/packages/shim/callout/README.md @@ -0,0 +1,18 @@ +# Callout compatibility shim + +`@fluentui-react-native/callout` preserves its existing named exports by +re-exporting the implementation and public types from +`@fluentui-react-native/native-core`. + +New consumers should import `Callout`, `CalloutProps`, and `CalloutHandle` +from `@fluentui-react-native/native-core`. Deprecated compatibility aliases +remain available through this shim. + +This package owns no native code, codegen specification, pod, or Windows +project. Native applications must list `@fluentui-react-native/native-core` +as a direct dependency so native tooling discovers its pod and Windows +Fabric library. Remove explicit `FRNCallout` pod declarations and regenerate +autolinking/Pods after updating. + +See the [Callout contract](../../agentic/native-core/src/components/callout/SPEC.md) +and [native-core organization](../../agentic/native-core/README.md). diff --git a/packages/native/Callout/jest.config.cjs b/packages/shim/callout/jest.config.cjs similarity index 100% rename from packages/native/Callout/jest.config.cjs rename to packages/shim/callout/jest.config.cjs diff --git a/packages/native/Callout/package.json b/packages/shim/callout/package.json similarity index 77% rename from packages/native/Callout/package.json rename to packages/shim/callout/package.json index 62402c199f..5a99dda312 100644 --- a/packages/native/Callout/package.json +++ b/packages/shim/callout/package.json @@ -1,16 +1,24 @@ { "name": "@fluentui-react-native/callout", "version": "0.29.6", - "description": "A cross-platform Callout component using the Fluent Design System", + "description": "Compatibility shim for the native-core Callout component.", "homepage": "https://github.com/microsoft/fluentui-react-native", "license": "MIT", "author": "", "repository": { "type": "git", "url": "https://github.com/microsoft/fluentui-react-native.git", - "directory": "packages/native/Callout" + "directory": "packages/shim/callout" }, + "files": [ + "lib/index.js", + "lib/index.js.map", + "lib/index.d.ts", + "lib/index.d.ts.map", + "src/index.ts" + ], "type": "module", + "sideEffects": false, "main": "lib/index.js", "module": "lib/index.js", "types": "lib/index.d.ts", @@ -31,7 +39,7 @@ "update-snapshots": "fluentui-scripts jest -u" }, "dependencies": { - "@fluentui-react-native/framework-base": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" }, "devDependencies": { "@babel/core": "catalog:", @@ -74,32 +82,9 @@ "optional": true } }, - "codegenConfig": { - "name": "FRNCalloutSpec", - "type": "all", - "jsSrcsDir": "src", - "ios": { - "componentProvider": { - "Callout": "RCTCalloutComponentView" - } - }, - "windows": { - "generators": "componentsWindows", - "namespace": "winrt::FluentUI::Callout::Codegen", - "outputDirectory": "windows/Callout/codegen", - "separateDataTypes": true - } - }, "furn": { "jestPlatform": "win32" }, - "react-native-windows": { - "init-windows": { - "name": "Callout", - "namespace": "FluentUI.Callout", - "template": "cpp-lib" - } - }, "rnx-kit": { "kitType": "library", "alignDeps": { diff --git a/packages/shim/callout/src/index.test.ts b/packages/shim/callout/src/index.test.ts new file mode 100644 index 0000000000..134fd33cf1 --- /dev/null +++ b/packages/shim/callout/src/index.test.ts @@ -0,0 +1,22 @@ +import { Callout, calloutName } from './index'; +import { Callout as NativeCallout, calloutName as nativeCalloutName } from '@fluentui-react-native/native-core'; +import type { CalloutHandle, CalloutProps, ICalloutProps, ICalloutTokens } from './index'; +import type { CalloutHandle as NativeCalloutHandle, CalloutProps as NativeCalloutProps } from '@fluentui-react-native/native-core'; + +const props: ICalloutProps & ICalloutTokens = { directionalHint: 'bottomCenter' }; +const nativeProps: NativeCalloutProps = props; +const legacyProps: CalloutProps = nativeProps; +const handle: NativeCalloutHandle = { blurWindow() {}, focusWindow() {} }; +const legacyHandle: CalloutHandle = handle; + +describe('Callout compatibility shim', () => { + it('re-exports the exact native-core component and name', () => { + expect(Callout).toBe(NativeCallout); + expect(calloutName).toBe(nativeCalloutName); + }); + + it('preserves public and deprecated type contracts', () => { + expect(legacyProps).toBe(props); + expect(legacyHandle).toBe(handle); + }); +}); diff --git a/packages/native/Callout/src/index.ts b/packages/shim/callout/src/index.ts similarity index 60% rename from packages/native/Callout/src/index.ts rename to packages/shim/callout/src/index.ts index 9925f9225e..235b9951ed 100644 --- a/packages/native/Callout/src/index.ts +++ b/packages/shim/callout/src/index.ts @@ -1,4 +1,4 @@ -export { calloutName } from './Callout.types'; +export { Callout, calloutName } from '@fluentui-react-native/native-core'; export type { CalloutHandle, CalloutNativeCommands, @@ -9,5 +9,4 @@ export type { ICalloutProps, ICalloutTokens, RestoreFocusEvent, -} from './Callout.types'; -export { Callout } from './Callout'; +} from '@fluentui-react-native/native-core'; diff --git a/packages/native/Callout/tsconfig.json b/packages/shim/callout/tsconfig.json similarity index 87% rename from packages/native/Callout/tsconfig.json rename to packages/shim/callout/tsconfig.json index d13fbc90df..a1c5ec1e71 100644 --- a/packages/native/Callout/tsconfig.json +++ b/packages/shim/callout/tsconfig.json @@ -10,7 +10,7 @@ "exclude": ["**/*.stories.ts", "**/*.stories.tsx"], "references": [ { - "path": "../../framework-base/tsconfig.json" + "path": "../../agentic/native-core/tsconfig.json" }, { "path": "../../../scripts/tsconfig.json" diff --git a/packages/components/FocusZone/CHANGELOG.json b/packages/shim/focus-zone/CHANGELOG.json similarity index 100% rename from packages/components/FocusZone/CHANGELOG.json rename to packages/shim/focus-zone/CHANGELOG.json diff --git a/packages/components/FocusZone/CHANGELOG.md b/packages/shim/focus-zone/CHANGELOG.md similarity index 100% rename from packages/components/FocusZone/CHANGELOG.md rename to packages/shim/focus-zone/CHANGELOG.md diff --git a/packages/shim/focus-zone/README.md b/packages/shim/focus-zone/README.md new file mode 100644 index 0000000000..69f23ccb57 --- /dev/null +++ b/packages/shim/focus-zone/README.md @@ -0,0 +1,19 @@ +# FocusZone compatibility shim + +`@fluentui-react-native/focus-zone` preserves its existing named exports by +re-exporting the implementation and public types from +`@fluentui-react-native/native-core`. Its legacy `NativeProps` export aliases +the component-qualified `FocusZoneNativeProps` export. + +New consumers should import `FocusZone` and `FocusZoneProps` from +`@fluentui-react-native/native-core`. Deprecated compatibility types remain +available through this shim. + +This package owns no native code, codegen specification, pod, or Windows +project. Native applications must list `@fluentui-react-native/native-core` +as a direct dependency so native tooling discovers its pod and Windows +Fabric library. Remove explicit `RCTFocusZone` pod declarations and regenerate +autolinking/Pods after updating. Win32 keeps its host-provided native component. + +See the [FocusZone contract](../../agentic/native-core/src/components/focus-zone/SPEC.md) +and [native-core organization](../../agentic/native-core/README.md). diff --git a/packages/shim/focus-zone/jest.config.cjs b/packages/shim/focus-zone/jest.config.cjs new file mode 100644 index 0000000000..b391f5b662 --- /dev/null +++ b/packages/shim/focus-zone/jest.config.cjs @@ -0,0 +1 @@ +module.exports = require('@fluentui-react-native/scripts/jest-config'); diff --git a/packages/components/FocusZone/package.json b/packages/shim/focus-zone/package.json similarity index 74% rename from packages/components/FocusZone/package.json rename to packages/shim/focus-zone/package.json index 1adc1d604c..bb222eb5c9 100644 --- a/packages/components/FocusZone/package.json +++ b/packages/shim/focus-zone/package.json @@ -1,15 +1,23 @@ { "name": "@fluentui-react-native/focus-zone", "version": "0.23.6", - "description": "A cross-platform FocusZone component using the Fluent Design System", + "description": "Compatibility shim for the native-core FocusZone component.", "license": "MIT", "author": "", "repository": { "type": "git", "url": "https://github.com/microsoft/fluentui-react-native.git", - "directory": "packages/components/FocusZone" + "directory": "packages/shim/focus-zone" }, + "files": [ + "lib/index.js", + "lib/index.js.map", + "lib/index.d.ts", + "lib/index.d.ts.map", + "src/index.ts" + ], "type": "module", + "sideEffects": false, "main": "lib/index.js", "module": "lib/index.js", "types": "lib/index.d.ts", @@ -30,12 +38,10 @@ "update-snapshots": "fluentui-scripts jest -u" }, "dependencies": { - "@fluentui-react-native/framework-base": "workspace:*", - "@fluentui-react-native/interactive-hooks": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" }, "devDependencies": { "@babel/core": "catalog:", - "@fluentui-react-native/desktop-driver": "workspace:*", "@fluentui-react-native/scripts": "workspace:*", "@office-iss/react-native-win32": "^0.81.8", "@react-native-community/cli": "^20.0.0", @@ -75,32 +81,9 @@ "optional": true } }, - "codegenConfig": { - "name": "FRNFocusZoneSpec", - "type": "all", - "jsSrcsDir": "src", - "ios": { - "componentProvider": { - "FocusZone": "RCTFocusZoneComponentView" - } - }, - "windows": { - "generators": "componentsWindows", - "namespace": "FRNFocusZoneCodegen", - "outputDirectory": "windows/FRNFocusZone/codegen", - "separateDataTypes": true - } - }, "furn": { "jestPlatform": "win32" }, - "react-native-windows": { - "init-windows": { - "name": "FRNFocusZone", - "namespace": "FRNFocusZone", - "template": "cpp-lib" - } - }, "rnx-kit": { "kitType": "library", "alignDeps": { diff --git a/packages/shim/focus-zone/src/index.test.ts b/packages/shim/focus-zone/src/index.test.ts new file mode 100644 index 0000000000..f7de321dbe --- /dev/null +++ b/packages/shim/focus-zone/src/index.test.ts @@ -0,0 +1,26 @@ +import { FocusZone, focusZoneName } from './index'; +import { FocusZone as NativeFocusZone, focusZoneName as nativeFocusZoneName } from '@fluentui-react-native/native-core'; +import type { FocusZoneProps, FocusZoneRenderData, FocusZoneState, FocusZoneTokens, FocusZoneType, NativeProps } from './index'; +import type { FocusZoneNativeProps, FocusZoneProps as NativeFocusZoneProps } from '@fluentui-react-native/native-core'; + +const props: FocusZoneProps = { focusZoneDirection: 'horizontal', isCircularNavigation: true }; +const nativeProps: NativeFocusZoneProps = props; +const nativeRootProps: FocusZoneNativeProps = { navigateAtEnd: 'NavigateWrap' }; +const legacyRootProps: NativeProps = nativeRootProps; +const state: FocusZoneState = {}; +const tokens: FocusZoneTokens = {}; +const renderData: FocusZoneRenderData = { slotProps: { root: legacyRootProps }, state }; +const legacyType: FocusZoneType = { props, tokens, slotProps: renderData.slotProps, state }; + +describe('FocusZone compatibility shim', () => { + it('re-exports the exact native-core component and name', () => { + expect(FocusZone).toBe(NativeFocusZone); + expect(focusZoneName).toBe(nativeFocusZoneName); + }); + + it('preserves public, native, and deprecated type contracts', () => { + expect(nativeProps).toBe(props); + expect(legacyRootProps).toBe(nativeRootProps); + expect(legacyType.state).toBe(state); + }); +}); diff --git a/packages/components/FocusZone/src/index.ts b/packages/shim/focus-zone/src/index.ts similarity index 54% rename from packages/components/FocusZone/src/index.ts rename to packages/shim/focus-zone/src/index.ts index f84aa91575..3c25d28d3d 100644 --- a/packages/components/FocusZone/src/index.ts +++ b/packages/shim/focus-zone/src/index.ts @@ -1,4 +1,4 @@ -export { focusZoneName } from './FocusZone.types'; +export { FocusZone, focusZoneName } from '@fluentui-react-native/native-core'; export type { FocusZoneDirection, FocusZoneProps, @@ -8,7 +8,6 @@ export type { FocusZoneTabNavigation, FocusZoneTokens, FocusZoneType, - NativeProps, + FocusZoneNativeProps as NativeProps, NavigateAtEnd, -} from './FocusZone.types'; -export { FocusZone } from './FocusZone'; +} from '@fluentui-react-native/native-core'; diff --git a/packages/components/FocusZone/tsconfig.json b/packages/shim/focus-zone/tsconfig.json similarity index 65% rename from packages/components/FocusZone/tsconfig.json rename to packages/shim/focus-zone/tsconfig.json index 243ef12c40..a1c5ec1e71 100644 --- a/packages/components/FocusZone/tsconfig.json +++ b/packages/shim/focus-zone/tsconfig.json @@ -10,13 +10,7 @@ "exclude": ["**/*.stories.ts", "**/*.stories.tsx"], "references": [ { - "path": "../../agentic/desktop-driver/tsconfig.json" - }, - { - "path": "../../framework-base/tsconfig.json" - }, - { - "path": "../../utils/interactive-hooks/tsconfig.json" + "path": "../../agentic/native-core/tsconfig.json" }, { "path": "../../../scripts/tsconfig.json" diff --git a/tsconfig.json b/tsconfig.json index 2d951847c5..1bb404723f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -64,9 +64,6 @@ { "path": "packages/components/FocusTrapZone/tsconfig.json" }, - { - "path": "packages/components/FocusZone/tsconfig.json" - }, { "path": "packages/components/Icon/tsconfig.json" }, @@ -209,7 +206,10 @@ "path": "packages/libraries/core/tsconfig.json" }, { - "path": "packages/native/Callout/tsconfig.json" + "path": "packages/shim/callout/tsconfig.json" + }, + { + "path": "packages/shim/focus-zone/tsconfig.json" }, { "path": "packages/shim/theme/tsconfig.json" diff --git a/yarn.lock b/yarn.lock index 9357564ab9..3273416e4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2565,10 +2565,9 @@ __metadata: resolution: "@fluentui-react-native/agentic-components-storybook@workspace:apps/storybook" dependencies: "@babel/core": "catalog:" - "@fluentui-react-native/callout": "workspace:*" "@fluentui-react-native/components": "workspace:*" "@fluentui-react-native/desktop-driver": "workspace:*" - "@fluentui-react-native/focus-zone": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" "@fluentui-react-native/storybook-desktop": "workspace:*" "@fluentui-react-native/storybook-desktop-runtime": "workspace:*" @@ -2852,12 +2851,12 @@ __metadata: languageName: unknown linkType: soft -"@fluentui-react-native/callout@workspace:*, @fluentui-react-native/callout@workspace:packages/native/Callout": +"@fluentui-react-native/callout@workspace:*, @fluentui-react-native/callout@workspace:packages/shim/callout": version: 0.0.0-use.local - resolution: "@fluentui-react-native/callout@workspace:packages/native/Callout" + resolution: "@fluentui-react-native/callout@workspace:packages/shim/callout" dependencies: "@babel/core": "catalog:" - "@fluentui-react-native/framework-base": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" "@office-iss/react-native-win32": "npm:^0.81.8" "@react-native-community/cli": "npm:^20.0.0" @@ -3017,11 +3016,10 @@ __metadata: resolution: "@fluentui-react-native/components@workspace:packages/agentic/components" dependencies: "@babel/core": "catalog:" - "@fluentui-react-native/callout": "workspace:*" "@fluentui-react-native/design": "workspace:*" "@fluentui-react-native/desktop-driver": "workspace:*" - "@fluentui-react-native/focus-zone": "workspace:*" "@fluentui-react-native/framework-base": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" "@fluentui-react-native/storybook-desktop": "workspace:*" "@office-iss/react-native-win32": "npm:^0.81.0" @@ -4112,14 +4110,12 @@ __metadata: languageName: unknown linkType: soft -"@fluentui-react-native/focus-zone@workspace:*, @fluentui-react-native/focus-zone@workspace:packages/components/FocusZone": +"@fluentui-react-native/focus-zone@workspace:*, @fluentui-react-native/focus-zone@workspace:packages/shim/focus-zone": version: 0.0.0-use.local - resolution: "@fluentui-react-native/focus-zone@workspace:packages/components/FocusZone" + resolution: "@fluentui-react-native/focus-zone@workspace:packages/shim/focus-zone" dependencies: "@babel/core": "catalog:" - "@fluentui-react-native/desktop-driver": "workspace:*" - "@fluentui-react-native/framework-base": "workspace:*" - "@fluentui-react-native/interactive-hooks": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" "@office-iss/react-native-win32": "npm:^0.81.8" "@react-native-community/cli": "npm:^20.0.0" @@ -4515,11 +4511,48 @@ __metadata: languageName: unknown linkType: soft -"@fluentui-react-native/native-core@workspace:packages/agentic/native-core": +"@fluentui-react-native/native-core@workspace:*, @fluentui-react-native/native-core@workspace:packages/agentic/native-core": version: 0.0.0-use.local resolution: "@fluentui-react-native/native-core@workspace:packages/agentic/native-core" dependencies: + "@babel/core": "catalog:" + "@fluentui-react-native/framework-base": "workspace:*" + "@fluentui-react-native/interactive-hooks": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" + "@office-iss/react-native-win32": "npm:^0.81.8" + "@react-native-community/cli": "npm:^20.0.0" + "@react-native-community/cli-platform-android": "npm:^20.0.0" + "@react-native-community/cli-platform-ios": "npm:^20.0.0" + "@react-native-windows/cli": "npm:^0.81.0" + "@react-native/babel-preset": "npm:^0.81.0" + "@react-native/metro-config": "npm:^0.81.0" + "@storybook/react-native": "npm:^10.4.7" + "@testing-library/react-native": "catalog:" + "@types/react": "npm:~19.1.4" + "@types/react-test-renderer": "npm:^19.1.0" + react: "npm:19.1.4" + react-native: "npm:^0.81.6" + react-native-macos: "npm:^0.81.0" + react-native-windows: "npm:^0.81.0" + react-test-renderer: "npm:19.1.4" + storybook: "npm:^10.4.0" + test-renderer: "catalog:" + peerDependencies: + "@office-iss/react-native-win32": ^0.74.0 || ^0.81.0 + "@types/react": ~18.2.0 || ~19.0.0 || ~19.1.4 + react: 18.2.0 || 19.0.0 || 19.1.4 + react-native: ^0.73.0 || ^0.74.0 || ^0.78.0 || ^0.81.6 + react-native-macos: ^0.73.0 || ^0.74.0 || ^0.78.0 || ^0.81.0 + react-native-windows: ^0.73.0 || ^0.74.0 || ^0.78.0 || ^0.81.0 + peerDependenciesMeta: + "@office-iss/react-native-win32": + optional: true + "@types/react": + optional: true + react-native-macos: + optional: true + react-native-windows: + optional: true languageName: unknown linkType: soft @@ -5060,9 +5093,9 @@ __metadata: resolution: "@fluentui-react-native/storybook-desktop-runtime@workspace:packages/agentic/storybook-desktop-runtime" dependencies: "@babel/core": "catalog:" - "@fluentui-react-native/callout": "workspace:*" "@fluentui-react-native/default-theme": "workspace:*" "@fluentui-react-native/design": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" "@office-iss/react-native-win32": "npm:^0.81.0" "@react-native-community/cli": "npm:^20.0.0" @@ -5485,6 +5518,7 @@ __metadata: "@fluentui-react-native/experimental-shimmer": "workspace:*" "@fluentui-react-native/focus-zone": "workspace:*" "@fluentui-react-native/menu-button": "workspace:*" + "@fluentui-react-native/native-core": "workspace:*" "@fluentui-react-native/radio-group": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" "@fluentui-react-native/tester-core": "workspace:*" From 666bcdd6701e03b9463b0b15d703f3526b6e9264 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 2 Oct 2026 13:37:09 -0700 Subject: [PATCH 3/5] move existing implementations to legacy submodule --- .changeset/native-core-legacy-entrypoint.md | 9 +++ AGENTS.md | 3 +- apps/storybook/README.md | 3 +- .../agentic/components/WIN32-FOCUS-PLAN.md | 2 +- .../focus-zone/focus-zone.stories.tsx | 4 +- packages/agentic/native-core/README.md | 55 ++++++++++++------- packages/agentic/native-core/package.json | 6 ++ packages/agentic/native-core/src/index.ts | 28 +--------- .../callout/Callout.stories.tsx | 0 .../callout/Callout.tsx | 0 .../callout/Callout.types.ts | 0 .../{components => legacy}/callout/SPEC.md | 5 +- .../callout/__tests__/Callout.test.tsx | 0 .../callout/__tests__/Callout.types.test.ts | 0 .../__snapshots__/Callout.test.tsx.snap | 0 .../focus-zone/FocusZone.tsx | 0 .../focus-zone/FocusZone.types.ts | 0 .../{components => legacy}/focus-zone/SPEC.md | 3 + .../focus-zone/__tests__/FocusZone.test.tsx | 0 .../__tests__/FocusZone.types.test.ts | 0 .../agentic/native-core/src/legacy/index.ts | 27 +++++++++ .../src/legacy/legacy.types.test.ts | 30 ++++++++++ .../native-core/tests/entrypoints.test.mjs | 11 +++- .../tests/native-ownership.test.mjs | 2 +- .../src/Win32CalloutPortal.tsx | 4 +- .../deprecated/foundation-compose/AGENTS.md | 2 +- packages/shim/callout/README.md | 6 +- packages/shim/callout/src/index.test.ts | 4 +- packages/shim/callout/src/index.ts | 4 +- packages/shim/focus-zone/README.md | 6 +- packages/shim/focus-zone/src/index.test.ts | 4 +- packages/shim/focus-zone/src/index.ts | 4 +- 32 files changed, 151 insertions(+), 71 deletions(-) create mode 100644 .changeset/native-core-legacy-entrypoint.md rename packages/agentic/native-core/src/{components => legacy}/callout/Callout.stories.tsx (100%) rename packages/agentic/native-core/src/{components => legacy}/callout/Callout.tsx (100%) rename packages/agentic/native-core/src/{components => legacy}/callout/Callout.types.ts (100%) rename packages/agentic/native-core/src/{components => legacy}/callout/SPEC.md (91%) rename packages/agentic/native-core/src/{components => legacy}/callout/__tests__/Callout.test.tsx (100%) rename packages/agentic/native-core/src/{components => legacy}/callout/__tests__/Callout.types.test.ts (100%) rename packages/agentic/native-core/src/{components => legacy}/callout/__tests__/__snapshots__/Callout.test.tsx.snap (100%) rename packages/agentic/native-core/src/{components => legacy}/focus-zone/FocusZone.tsx (100%) rename packages/agentic/native-core/src/{components => legacy}/focus-zone/FocusZone.types.ts (100%) rename packages/agentic/native-core/src/{components => legacy}/focus-zone/SPEC.md (95%) rename packages/agentic/native-core/src/{components => legacy}/focus-zone/__tests__/FocusZone.test.tsx (100%) rename packages/agentic/native-core/src/{components => legacy}/focus-zone/__tests__/FocusZone.types.test.ts (100%) create mode 100644 packages/agentic/native-core/src/legacy/index.ts create mode 100644 packages/agentic/native-core/src/legacy/legacy.types.test.ts diff --git a/.changeset/native-core-legacy-entrypoint.md b/.changeset/native-core-legacy-entrypoint.md new file mode 100644 index 0000000000..72f599131c --- /dev/null +++ b/.changeset/native-core-legacy-entrypoint.md @@ -0,0 +1,9 @@ +--- +"@fluentui-react-native/native-core": minor +"@fluentui-react-native/callout": patch +"@fluentui-react-native/focus-zone": patch +"@fluentui-react-native/components": patch +"@fluentui-react-native/storybook-desktop-runtime": patch +--- + +Isolate the existing Callout and FocusZone JavaScript wrappers under native-core/legacy instead of the package root. Compatibility shims retain their exports through this submodule; native implementations and codegen specifications are unchanged. diff --git a/AGENTS.md b/AGENTS.md index f05cbd3606..fe2e40686a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -275,7 +275,8 @@ The composition framework uses precise types for better type safety: - **Do not use barrel exports (`export * from '...'`)** - wildcard re-exports break tree-shaking because bundlers cannot statically determine which symbols are used, so unused code is retained in consumers' bundles. Always use explicit named re-exports instead, e.g. `export { Foo, Bar } from './module'` and `export type { Baz } from './module'`. **Native Modules**: Callout and FocusZone implementations live in `@fluentui-react-native/native-core`; their former packages -are JS-only compatibility shims under `/packages/shim/`. Components with native code: +are JS-only compatibility shims under `/packages/shim/`. Their JavaScript wrappers live in `src/legacy` and are exported +only from `@fluentui-react-native/native-core/legacy`, not native-core's root entrypoint. Components with native code: - Typically have one root slot wrapping the native component - Use `codegenNativeComponent` for new architecture compatibility diff --git a/apps/storybook/README.md b/apps/storybook/README.md index ee18b76a50..b34184c251 100644 --- a/apps/storybook/README.md +++ b/apps/storybook/README.md @@ -3,7 +3,8 @@ On-device [Storybook](https://storybook.js.org/) test app (Storybook for React Native v10) for `@fluentui-react-native/components` and `@fluentui-react-native/native-core`. It loads every `*.stories.(ts|tsx)` file from the agentic components package plus native-core's Callout -stories. FocusZone stories remain agentic primitive stories and use native-core's implementation. +stories. FocusZone stories remain agentic primitive stories and use native-core's +`legacy` entrypoint, as does the Win32 Callout portal. Native-core owns the shared macOS pod and Windows Fabric library for both components. The reusable desktop CLI and configuration live in diff --git a/packages/agentic/components/WIN32-FOCUS-PLAN.md b/packages/agentic/components/WIN32-FOCUS-PLAN.md index c857fe0509..93dc5b7123 100644 --- a/packages/agentic/components/WIN32-FOCUS-PLAN.md +++ b/packages/agentic/components/WIN32-FOCUS-PLAN.md @@ -246,7 +246,7 @@ paths. The installed Win32 JavaScript inspected was `packages\components\Menu\src\MenuPopover\useMenuPopover.ts:42-84,100-118`. - **V6:** `packages\components\TabList\src\Tab\useTab.win32.ts:64-110,142-152`; `packages\components\TabList\src\TabList\useTabList.ts:142-176,183-200`. -- **V7:** `packages\agentic\native-core\src\components\focus-zone\FocusZone.tsx:15-45`; +- **V7:** `packages\agentic\native-core\src\legacy\focus-zone\FocusZone.tsx:15-45`; `packages\components\FocusTrapZone\src\FocusTrapZone.ts:15-31`. These wrappers do not by themselves prove native trap/restoration semantics. - **V8:** `apps\tester-core\src\TestComponents\FocusZone\FocusZoneE2ETest.tsx:1-120`; diff --git a/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx b/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx index 2463df8fe9..15af215ab2 100644 --- a/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx +++ b/packages/agentic/components/src/primitives/focus-zone/focus-zone.stories.tsx @@ -4,8 +4,8 @@ import { Platform, Pressable, StyleSheet, Text, View } from 'react-native'; import type { StyleProp, ViewStyle } from 'react-native'; import type { WdioStory } from '@fluentui-react-native/storybook-desktop/testing'; -import { FocusZone } from '@fluentui-react-native/native-core'; -import type { FocusZoneDirection, FocusZoneProps, FocusZoneTabNavigation } from '@fluentui-react-native/native-core'; +import { FocusZone } from '@fluentui-react-native/native-core/legacy'; +import type { FocusZoneDirection, FocusZoneProps, FocusZoneTabNavigation } from '@fluentui-react-native/native-core/legacy'; import type { Meta, StoryObj } from '@storybook/react-native'; import { Button } from '../../components/button/button'; diff --git a/packages/agentic/native-core/README.md b/packages/agentic/native-core/README.md index d1dba69b34..6c741271fb 100644 --- a/packages/agentic/native-core/README.md +++ b/packages/agentic/native-core/README.md @@ -9,16 +9,27 @@ dependency. ## Current contents -The root exports the existing unstyled `Callout` and `FocusZone` wrappers and -their public types. Their JS, tests, specifications, macOS implementations, -and Windows Fabric implementations live here. The `macos`, `windows`, `win`, -and `win32` entrypoints are reserved for future host-specific APIs and remain -empty; shared components belong to the root. +The existing unstyled `Callout` and `FocusZone` JavaScript wrappers, public +types, tests, stories, and specifications live under `src/legacy` and are +exported only from `@fluentui-react-native/native-core/legacy`. They are not +exported by the root entrypoint, which is reserved for modern cross-platform +APIs. The `macos`, `windows`, `win`, and `win32` entrypoints are reserved for +future host-specific APIs and remain empty. `@fluentui-react-native/callout` and `@fluentui-react-native/focus-zone` are JS-only compatibility shims under `packages/shim`. Deprecated type aliases and -native registration names are preserved. The root uses the component-qualified -`FocusZoneNativeProps`; the FocusZone shim retains its old `NativeProps` name. +native registration names are preserved. The legacy entrypoint uses the +component-qualified `FocusZoneNativeProps`; the FocusZone shim retains its old +`NativeProps` name. + +```ts +import { Callout, FocusZone } from '@fluentui-react-native/native-core/legacy'; +import type { CalloutProps, FocusZoneProps } from '@fluentui-react-native/native-core/legacy'; +``` + +Native implementations and shared codegen inputs remain outside `src/legacy`; +the legacy boundary applies to the JavaScript component API, not native +ownership or renderer support. Native applications must directly depend on this package for autolinking. macOS now uses one `FRNNativeCore` pod, and Windows uses one @@ -29,16 +40,17 @@ to use its host-provided `RCTCallout` and `RCTFocusZone`. ## Public entrypoints -| Import | Scope | Source entrypoint | -| -------------------------------------------- | --------------------------------------- | ---------------------- | -| `@fluentui-react-native/native-core` | Cross-platform APIs | `src/index.ts` | -| `@fluentui-react-native/native-core/macos` | macOS-specific APIs | `src/macos/index.ts` | -| `@fluentui-react-native/native-core/windows` | React Native Windows-specific APIs | `src/windows/index.ts` | -| `@fluentui-react-native/native-core/win` | APIs shared by Windows and Win32 | `src/win/index.ts` | -| `@fluentui-react-native/native-core/win32` | Office React Native Win32-specific APIs | `src/win32/index.ts` | +| Import | Scope | Source entrypoint | +| -------------------------------------------- | ------------------------------------------- | ---------------------- | +| `@fluentui-react-native/native-core` | Cross-platform APIs | `src/index.ts` | +| `@fluentui-react-native/native-core/legacy` | Legacy Callout/FocusZone wrappers and types | `src/legacy/index.ts` | +| `@fluentui-react-native/native-core/macos` | macOS-specific APIs | `src/macos/index.ts` | +| `@fluentui-react-native/native-core/windows` | React Native Windows-specific APIs | `src/windows/index.ts` | +| `@fluentui-react-native/native-core/win` | APIs shared by Windows and Win32 | `src/win/index.ts` | +| `@fluentui-react-native/native-core/win32` | Office React Native Win32-specific APIs | `src/win32/index.ts` | Each entrypoint explicitly exports components, module facades, and their -public types. The root is not an umbrella export of the platform submodules; +public types. The root does not re-export legacy or platform submodules; `win` is not an umbrella export of `windows` and `win32`. Give an API its narrowest applicable public home. Shared implementation does not itself make an API cross-platform. @@ -57,9 +69,9 @@ imports. Never use wildcard re-exports. ## JavaScript and specification layout -Component wrappers live in `src/components/callout` and -`src/components/focus-zone`, with codegen inputs in `src/specs/components`. -Add module and internal utility directories as real features arrive: +Legacy wrappers live in `src/legacy/callout` and `src/legacy/focus-zone`, with +shared codegen inputs in `src/specs/components`. Reserve `src/components` for +modern wrappers and add module/internal directories as real features arrive: ```text src/ @@ -68,6 +80,10 @@ src/ windows/index.ts win/index.ts win32/index.ts + legacy/ + index.ts Explicit legacy-only public exports + callout/ Existing Callout wrapper, types, tests, and stories + focus-zone/ Existing FocusZone wrapper, types, and tests components/ / .tsx Thin public wrapper, when shared @@ -209,10 +225,11 @@ yarn workspace @fluentui-react-native/native-core codegen:windows --check yarn build ``` -Node tests validate the five export maps, emitted JS/declaration files, +Node tests validate the six export maps, emitted JS/declaration files, conditional resolution, shared native ownership, and JS-only shims. Colocated Jest tests retain wrapper behavior, imperative refs/commands, slot acceptance, and public type contracts; shim tests verify exact component identity. +Runtime and compile-time checks reject legacy component/type exports at root. The package prebuild regenerates Windows bindings from the shared spec. Native verification must cover registration, events/commands, refs, unmount cleanup, diff --git a/packages/agentic/native-core/package.json b/packages/agentic/native-core/package.json index 408487ba1f..b31e76f650 100644 --- a/packages/agentic/native-core/package.json +++ b/packages/agentic/native-core/package.json @@ -41,6 +41,12 @@ "import": "./lib/index.js", "default": "./src/index.ts" }, + "./legacy": { + "types": "./lib/legacy/index.d.ts", + "react-native": "./src/legacy/index.ts", + "import": "./lib/legacy/index.js", + "default": "./src/legacy/index.ts" + }, "./macos": { "types": "./lib/macos/index.d.ts", "react-native": "./src/macos/index.ts", diff --git a/packages/agentic/native-core/src/index.ts b/packages/agentic/native-core/src/index.ts index a576fa7f8d..cb0ff5c3b5 100644 --- a/packages/agentic/native-core/src/index.ts +++ b/packages/agentic/native-core/src/index.ts @@ -1,27 +1 @@ -export { Callout } from './components/callout/Callout'; -export { calloutName } from './components/callout/Callout.types'; -export type { - CalloutHandle, - CalloutNativeCommands, - CalloutProps, - CalloutTokens, - DirectionalHint, - DismissBehaviors, - ICalloutProps, - ICalloutTokens, - RestoreFocusEvent, -} from './components/callout/Callout.types'; -export { FocusZone } from './components/focus-zone/FocusZone'; -export { focusZoneName } from './components/focus-zone/FocusZone.types'; -export type { - FocusZoneDirection, - FocusZoneProps, - FocusZoneRenderData, - FocusZoneSlotProps, - FocusZoneState, - FocusZoneTabNavigation, - FocusZoneTokens, - FocusZoneType, - NativeProps as FocusZoneNativeProps, - NavigateAtEnd, -} from './components/focus-zone/FocusZone.types'; +export {}; diff --git a/packages/agentic/native-core/src/components/callout/Callout.stories.tsx b/packages/agentic/native-core/src/legacy/callout/Callout.stories.tsx similarity index 100% rename from packages/agentic/native-core/src/components/callout/Callout.stories.tsx rename to packages/agentic/native-core/src/legacy/callout/Callout.stories.tsx diff --git a/packages/agentic/native-core/src/components/callout/Callout.tsx b/packages/agentic/native-core/src/legacy/callout/Callout.tsx similarity index 100% rename from packages/agentic/native-core/src/components/callout/Callout.tsx rename to packages/agentic/native-core/src/legacy/callout/Callout.tsx diff --git a/packages/agentic/native-core/src/components/callout/Callout.types.ts b/packages/agentic/native-core/src/legacy/callout/Callout.types.ts similarity index 100% rename from packages/agentic/native-core/src/components/callout/Callout.types.ts rename to packages/agentic/native-core/src/legacy/callout/Callout.types.ts diff --git a/packages/agentic/native-core/src/components/callout/SPEC.md b/packages/agentic/native-core/src/legacy/callout/SPEC.md similarity index 91% rename from packages/agentic/native-core/src/components/callout/SPEC.md rename to packages/agentic/native-core/src/legacy/callout/SPEC.md index e57ccfeac8..1e48b41be8 100644 --- a/packages/agentic/native-core/src/components/callout/SPEC.md +++ b/packages/agentic/native-core/src/legacy/callout/SPEC.md @@ -7,6 +7,9 @@ positioned relative to a target ref, registered native anchor, or anchor rectangle. Its JS wrapper, native adapters, and codegen schema are owned by `@fluentui-react-native/native-core`; the old Callout package is a JS-only shim. +The JavaScript component and its public types are exported only from +`@fluentui-react-native/native-core/legacy`, not the package root. + ## Contract - `CalloutProps` extends React Native `ViewProps` with target resolution, @@ -37,7 +40,7 @@ rectangle. Its JS wrapper, native adapters, and codegen schema are owned by ## Compatibility `ICalloutProps`, `ICalloutTokens`, and `CalloutNativeCommands` remain as -deprecated aliases for the modern public types. +deprecated aliases for the public types in the legacy entrypoint. Existing `Callout`/`RCTCallout` native registration names remain unchanged. Native applications must directly depend on `@fluentui-react-native/native-core` diff --git a/packages/agentic/native-core/src/components/callout/__tests__/Callout.test.tsx b/packages/agentic/native-core/src/legacy/callout/__tests__/Callout.test.tsx similarity index 100% rename from packages/agentic/native-core/src/components/callout/__tests__/Callout.test.tsx rename to packages/agentic/native-core/src/legacy/callout/__tests__/Callout.test.tsx diff --git a/packages/agentic/native-core/src/components/callout/__tests__/Callout.types.test.ts b/packages/agentic/native-core/src/legacy/callout/__tests__/Callout.types.test.ts similarity index 100% rename from packages/agentic/native-core/src/components/callout/__tests__/Callout.types.test.ts rename to packages/agentic/native-core/src/legacy/callout/__tests__/Callout.types.test.ts diff --git a/packages/agentic/native-core/src/components/callout/__tests__/__snapshots__/Callout.test.tsx.snap b/packages/agentic/native-core/src/legacy/callout/__tests__/__snapshots__/Callout.test.tsx.snap similarity index 100% rename from packages/agentic/native-core/src/components/callout/__tests__/__snapshots__/Callout.test.tsx.snap rename to packages/agentic/native-core/src/legacy/callout/__tests__/__snapshots__/Callout.test.tsx.snap diff --git a/packages/agentic/native-core/src/components/focus-zone/FocusZone.tsx b/packages/agentic/native-core/src/legacy/focus-zone/FocusZone.tsx similarity index 100% rename from packages/agentic/native-core/src/components/focus-zone/FocusZone.tsx rename to packages/agentic/native-core/src/legacy/focus-zone/FocusZone.tsx diff --git a/packages/agentic/native-core/src/components/focus-zone/FocusZone.types.ts b/packages/agentic/native-core/src/legacy/focus-zone/FocusZone.types.ts similarity index 100% rename from packages/agentic/native-core/src/components/focus-zone/FocusZone.types.ts rename to packages/agentic/native-core/src/legacy/focus-zone/FocusZone.types.ts diff --git a/packages/agentic/native-core/src/components/focus-zone/SPEC.md b/packages/agentic/native-core/src/legacy/focus-zone/SPEC.md similarity index 95% rename from packages/agentic/native-core/src/components/focus-zone/SPEC.md rename to packages/agentic/native-core/src/legacy/focus-zone/SPEC.md index 5379e8851c..2abe612905 100644 --- a/packages/agentic/native-core/src/components/focus-zone/SPEC.md +++ b/packages/agentic/native-core/src/legacy/focus-zone/SPEC.md @@ -7,6 +7,9 @@ keyboard navigation among focusable descendants. Its JS wrapper, native adapters, and codegen schema are owned by `@fluentui-react-native/native-core`; the old FocusZone package is a JS-only shim. +The JavaScript component and its public types are exported only from +`@fluentui-react-native/native-core/legacy`, not the package root. + ## Contract - `FocusZoneProps` extends React Native `ViewProps` with directional, circular, diff --git a/packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.test.tsx b/packages/agentic/native-core/src/legacy/focus-zone/__tests__/FocusZone.test.tsx similarity index 100% rename from packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.test.tsx rename to packages/agentic/native-core/src/legacy/focus-zone/__tests__/FocusZone.test.tsx diff --git a/packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.types.test.ts b/packages/agentic/native-core/src/legacy/focus-zone/__tests__/FocusZone.types.test.ts similarity index 100% rename from packages/agentic/native-core/src/components/focus-zone/__tests__/FocusZone.types.test.ts rename to packages/agentic/native-core/src/legacy/focus-zone/__tests__/FocusZone.types.test.ts diff --git a/packages/agentic/native-core/src/legacy/index.ts b/packages/agentic/native-core/src/legacy/index.ts new file mode 100644 index 0000000000..5ac07b734e --- /dev/null +++ b/packages/agentic/native-core/src/legacy/index.ts @@ -0,0 +1,27 @@ +export { Callout } from './callout/Callout'; +export { calloutName } from './callout/Callout.types'; +export type { + CalloutHandle, + CalloutNativeCommands, + CalloutProps, + CalloutTokens, + DirectionalHint, + DismissBehaviors, + ICalloutProps, + ICalloutTokens, + RestoreFocusEvent, +} from './callout/Callout.types'; +export { FocusZone } from './focus-zone/FocusZone'; +export { focusZoneName } from './focus-zone/FocusZone.types'; +export type { + FocusZoneDirection, + FocusZoneProps, + FocusZoneRenderData, + FocusZoneSlotProps, + FocusZoneState, + FocusZoneTabNavigation, + FocusZoneTokens, + FocusZoneType, + NativeProps as FocusZoneNativeProps, + NavigateAtEnd, +} from './focus-zone/FocusZone.types'; diff --git a/packages/agentic/native-core/src/legacy/legacy.types.test.ts b/packages/agentic/native-core/src/legacy/legacy.types.test.ts new file mode 100644 index 0000000000..2e516f8977 --- /dev/null +++ b/packages/agentic/native-core/src/legacy/legacy.types.test.ts @@ -0,0 +1,30 @@ +import * as root from '../index'; +import { Callout, FocusZone } from './index'; +import type { CalloutProps, FocusZoneProps } from './index'; + +const calloutProps: CalloutProps = { target: 'anchor' }; +const focusZoneProps: FocusZoneProps = { focusZoneDirection: 'horizontal' }; + +// @ts-expect-error CalloutProps is available only from the legacy entrypoint. +const rootCalloutProps: root.CalloutProps = calloutProps; +// @ts-expect-error FocusZoneProps is available only from the legacy entrypoint. +const rootFocusZoneProps: root.FocusZoneProps = focusZoneProps; + +// @ts-expect-error Callout is not exported from the root entrypoint. +const rootCalloutKey: keyof typeof root = 'Callout'; +// @ts-expect-error FocusZone is not exported from the root entrypoint. +const rootFocusZoneKey: keyof typeof root = 'FocusZone'; + +describe('Legacy entrypoint types', () => { + it('exposes the wrappers only from legacy', () => { + expect(Callout).toBeDefined(); + expect(FocusZone).toBeDefined(); + expect(root).not.toHaveProperty(rootCalloutKey); + expect(root).not.toHaveProperty(rootFocusZoneKey); + }); + + it('retains the legacy public prop contracts', () => { + expect(rootCalloutProps).toBe(calloutProps); + expect(rootFocusZoneProps).toBe(focusZoneProps); + }); +}); diff --git a/packages/agentic/native-core/tests/entrypoints.test.mjs b/packages/agentic/native-core/tests/entrypoints.test.mjs index 3fda319b2f..6eb5357d99 100644 --- a/packages/agentic/native-core/tests/entrypoints.test.mjs +++ b/packages/agentic/native-core/tests/entrypoints.test.mjs @@ -8,13 +8,14 @@ const packageRoot = new URL('../', import.meta.url); const manifest = JSON.parse(await readFile(new URL('package.json', packageRoot), 'utf8')); const entrypoints = [ ['.', 'index'], + ['./legacy', 'legacy/index'], ['./macos', 'macos/index'], ['./windows', 'windows/index'], ['./win', 'win/index'], ['./win32', 'win32/index'], ]; -test('declares exactly the five public entrypoints and package metadata', () => { +test('declares exactly the six public entrypoints and package metadata', () => { assert.equal(manifest.name, '@fluentui-react-native/native-core'); assert.deepEqual(Object.keys(manifest.exports), [...entrypoints.map(([entrypoint]) => entrypoint), './package.json']); assert.equal(manifest.exports['./package.json'], './package.json'); @@ -23,6 +24,14 @@ test('declares exactly the five public entrypoints and package metadata', () => assert.equal(manifest.types, 'lib/index.d.ts'); }); +test('the root entrypoint does not expose or initialize legacy components', async () => { + const root = await import('@fluentui-react-native/native-core'); + assert.ok(!('Callout' in root)); + assert.ok(!('FocusZone' in root)); + assert.ok(!('calloutName' in root)); + assert.ok(!('focusZoneName' in root)); +}); + for (const [entrypoint, path] of entrypoints) { test(`${entrypoint} has distinct source, JavaScript, and declaration targets`, async () => { const expected = { diff --git a/packages/agentic/native-core/tests/native-ownership.test.mjs b/packages/agentic/native-core/tests/native-ownership.test.mjs index bb24deee3d..12a85727fc 100644 --- a/packages/agentic/native-core/tests/native-ownership.test.mjs +++ b/packages/agentic/native-core/tests/native-ownership.test.mjs @@ -57,7 +57,7 @@ for (const shim of ['callout', 'focus-zone']) { const files = await readdir(root); assert.ok(!files.some((file) => file.endsWith('.podspec') || ['macos', 'windows', 'react-native.config.cjs'].includes(file))); const entrypoint = await readFile(new URL('src/index.ts', root), 'utf8'); - assert.match(entrypoint, /from '@fluentui-react-native\/native-core'/); + assert.match(entrypoint, /from '@fluentui-react-native\/native-core\/legacy'/); assert.doesNotMatch(entrypoint, /export \*/); }); } diff --git a/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx b/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx index af9f3eceb7..ee5b587a23 100644 --- a/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/Win32CalloutPortal.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { StyleSheet } from 'react-native'; -import { Callout } from '@fluentui-react-native/native-core'; -import type { CalloutProps, DirectionalHint } from '@fluentui-react-native/native-core'; +import { Callout } from '@fluentui-react-native/native-core/legacy'; +import type { CalloutProps, DirectionalHint } from '@fluentui-react-native/native-core/legacy'; import { RootInputBoundary } from '@fluentui-react-native/design'; import { useTheme } from '@storybook/react-native-theming'; diff --git a/packages/deprecated/foundation-compose/AGENTS.md b/packages/deprecated/foundation-compose/AGENTS.md index 8a179372b2..218573b309 100644 --- a/packages/deprecated/foundation-compose/AGENTS.md +++ b/packages/deprecated/foundation-compose/AGENTS.md @@ -147,7 +147,7 @@ automatically. `ref` during preparation, commonly with `useViewCommandFocus`; type ref-bearing roots with `React.PropsWithRef<...>`. For imperative native APIs, use an internal native ref plus `useImperativeHandle`, as in - `packages/agentic/native-core/src/components/callout/Callout.tsx`. + `packages/agentic/native-core/src/legacy/callout/Callout.tsx`. - Do not introduce `forwardRef` or a new public `ref` convention into an established v0 API without an explicit migration requirement. diff --git a/packages/shim/callout/README.md b/packages/shim/callout/README.md index af29596036..cb7c14ee15 100644 --- a/packages/shim/callout/README.md +++ b/packages/shim/callout/README.md @@ -2,10 +2,10 @@ `@fluentui-react-native/callout` preserves its existing named exports by re-exporting the implementation and public types from -`@fluentui-react-native/native-core`. +`@fluentui-react-native/native-core/legacy`. New consumers should import `Callout`, `CalloutProps`, and `CalloutHandle` -from `@fluentui-react-native/native-core`. Deprecated compatibility aliases +from `@fluentui-react-native/native-core/legacy`. Deprecated compatibility aliases remain available through this shim. This package owns no native code, codegen specification, pod, or Windows @@ -14,5 +14,5 @@ as a direct dependency so native tooling discovers its pod and Windows Fabric library. Remove explicit `FRNCallout` pod declarations and regenerate autolinking/Pods after updating. -See the [Callout contract](../../agentic/native-core/src/components/callout/SPEC.md) +See the [Callout contract](../../agentic/native-core/src/legacy/callout/SPEC.md) and [native-core organization](../../agentic/native-core/README.md). diff --git a/packages/shim/callout/src/index.test.ts b/packages/shim/callout/src/index.test.ts index 134fd33cf1..15a107f5be 100644 --- a/packages/shim/callout/src/index.test.ts +++ b/packages/shim/callout/src/index.test.ts @@ -1,7 +1,7 @@ import { Callout, calloutName } from './index'; -import { Callout as NativeCallout, calloutName as nativeCalloutName } from '@fluentui-react-native/native-core'; +import { Callout as NativeCallout, calloutName as nativeCalloutName } from '@fluentui-react-native/native-core/legacy'; import type { CalloutHandle, CalloutProps, ICalloutProps, ICalloutTokens } from './index'; -import type { CalloutHandle as NativeCalloutHandle, CalloutProps as NativeCalloutProps } from '@fluentui-react-native/native-core'; +import type { CalloutHandle as NativeCalloutHandle, CalloutProps as NativeCalloutProps } from '@fluentui-react-native/native-core/legacy'; const props: ICalloutProps & ICalloutTokens = { directionalHint: 'bottomCenter' }; const nativeProps: NativeCalloutProps = props; diff --git a/packages/shim/callout/src/index.ts b/packages/shim/callout/src/index.ts index 235b9951ed..0b95238000 100644 --- a/packages/shim/callout/src/index.ts +++ b/packages/shim/callout/src/index.ts @@ -1,4 +1,4 @@ -export { Callout, calloutName } from '@fluentui-react-native/native-core'; +export { Callout, calloutName } from '@fluentui-react-native/native-core/legacy'; export type { CalloutHandle, CalloutNativeCommands, @@ -9,4 +9,4 @@ export type { ICalloutProps, ICalloutTokens, RestoreFocusEvent, -} from '@fluentui-react-native/native-core'; +} from '@fluentui-react-native/native-core/legacy'; diff --git a/packages/shim/focus-zone/README.md b/packages/shim/focus-zone/README.md index 69f23ccb57..83130a9cd7 100644 --- a/packages/shim/focus-zone/README.md +++ b/packages/shim/focus-zone/README.md @@ -2,11 +2,11 @@ `@fluentui-react-native/focus-zone` preserves its existing named exports by re-exporting the implementation and public types from -`@fluentui-react-native/native-core`. Its legacy `NativeProps` export aliases +`@fluentui-react-native/native-core/legacy`. Its legacy `NativeProps` export aliases the component-qualified `FocusZoneNativeProps` export. New consumers should import `FocusZone` and `FocusZoneProps` from -`@fluentui-react-native/native-core`. Deprecated compatibility types remain +`@fluentui-react-native/native-core/legacy`. Deprecated compatibility types remain available through this shim. This package owns no native code, codegen specification, pod, or Windows @@ -15,5 +15,5 @@ as a direct dependency so native tooling discovers its pod and Windows Fabric library. Remove explicit `RCTFocusZone` pod declarations and regenerate autolinking/Pods after updating. Win32 keeps its host-provided native component. -See the [FocusZone contract](../../agentic/native-core/src/components/focus-zone/SPEC.md) +See the [FocusZone contract](../../agentic/native-core/src/legacy/focus-zone/SPEC.md) and [native-core organization](../../agentic/native-core/README.md). diff --git a/packages/shim/focus-zone/src/index.test.ts b/packages/shim/focus-zone/src/index.test.ts index f7de321dbe..00c6905dd3 100644 --- a/packages/shim/focus-zone/src/index.test.ts +++ b/packages/shim/focus-zone/src/index.test.ts @@ -1,7 +1,7 @@ import { FocusZone, focusZoneName } from './index'; -import { FocusZone as NativeFocusZone, focusZoneName as nativeFocusZoneName } from '@fluentui-react-native/native-core'; +import { FocusZone as NativeFocusZone, focusZoneName as nativeFocusZoneName } from '@fluentui-react-native/native-core/legacy'; import type { FocusZoneProps, FocusZoneRenderData, FocusZoneState, FocusZoneTokens, FocusZoneType, NativeProps } from './index'; -import type { FocusZoneNativeProps, FocusZoneProps as NativeFocusZoneProps } from '@fluentui-react-native/native-core'; +import type { FocusZoneNativeProps, FocusZoneProps as NativeFocusZoneProps } from '@fluentui-react-native/native-core/legacy'; const props: FocusZoneProps = { focusZoneDirection: 'horizontal', isCircularNavigation: true }; const nativeProps: NativeFocusZoneProps = props; diff --git a/packages/shim/focus-zone/src/index.ts b/packages/shim/focus-zone/src/index.ts index 3c25d28d3d..53614aef8d 100644 --- a/packages/shim/focus-zone/src/index.ts +++ b/packages/shim/focus-zone/src/index.ts @@ -1,4 +1,4 @@ -export { FocusZone, focusZoneName } from '@fluentui-react-native/native-core'; +export { FocusZone, focusZoneName } from '@fluentui-react-native/native-core/legacy'; export type { FocusZoneDirection, FocusZoneProps, @@ -10,4 +10,4 @@ export type { FocusZoneType, FocusZoneNativeProps as NativeProps, NavigateAtEnd, -} from '@fluentui-react-native/native-core'; +} from '@fluentui-react-native/native-core/legacy'; From c42f54fb15fcbfcf15fc926ec7253c6000f6d147 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 2 Oct 2026 14:23:02 -0700 Subject: [PATCH 4/5] Fix native-core macOS interoperability and validate migration Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/native-core-macos-interop.md | 5 +++ packages/agentic/native-core/README.md | 15 +++++++ .../components/Callout/shared/FRNCallout.h | 14 ------- .../native-core/macos/shared/FRNNativeCore.h | 2 + packages/agentic/native-core/package.json | 4 +- .../src/legacy/callout/Callout.stories.tsx | 40 ++++++++++++++++--- .../tests/native-ownership.test.mjs | 13 ++++++ .../agentic/native-core/tsconfig.stories.json | 19 +++++++++ yarn.lock | 1 + 9 files changed, 93 insertions(+), 20 deletions(-) create mode 100644 .changeset/native-core-macos-interop.md delete mode 100644 packages/agentic/native-core/macos/components/Callout/shared/FRNCallout.h create mode 100644 packages/agentic/native-core/macos/shared/FRNNativeCore.h create mode 100644 packages/agentic/native-core/tsconfig.stories.json diff --git a/.changeset/native-core-macos-interop.md b/.changeset/native-core-macos-interop.md new file mode 100644 index 0000000000..1395eefc1f --- /dev/null +++ b/.changeset/native-core-macos-interop.md @@ -0,0 +1,5 @@ +--- +'@fluentui-react-native/native-core': patch +--- + +Fix the macOS Swift interoperability header name for the consolidated native-core pod. diff --git a/packages/agentic/native-core/README.md b/packages/agentic/native-core/README.md index 6c741271fb..94f76086e5 100644 --- a/packages/agentic/native-core/README.md +++ b/packages/agentic/native-core/README.md @@ -38,6 +38,10 @@ explicit old `FRNCallout`/`RCTFocusZone` pod or standalone Windows project references and regenerate the consuming native project/Pods. Win32 continues to use its host-provided `RCTCallout` and `RCTFocusZone`. +The macOS module-named header at `macos/shared/FRNNativeCore.h` is required by +the generated `FRNNativeCore-Swift.h`; keep it aligned with the pod's +`module_name` when changing native ownership. + ## Public entrypoints | Import | Scope | Source entrypoint | @@ -234,3 +238,14 @@ The package prebuild regenerates Windows bindings from the shared spec. Native verification must cover registration, events/commands, refs, unmount cleanup, error propagation, and architecture/platform parity, not only JS mocks. +Callout's executable macOS Fabric story verifies native popup creation, `onShow` and +`onDismiss`, outside-click dismissal, and reopening. Run it together +with FocusZone's keyboard cases from `apps/storybook` using the owned lifecycle: + +```sh +STORYBOOK_SMOKE_STORY='native-*' yarn storybook smoke --macos --mode stories-and-tests +``` + +This traverses the full catalog before running the selected native tests. +The macOS Desktop Driver currently targets Fabric; a successful Paper build +does not establish Paper runtime or input parity. diff --git a/packages/agentic/native-core/macos/components/Callout/shared/FRNCallout.h b/packages/agentic/native-core/macos/components/Callout/shared/FRNCallout.h deleted file mode 100644 index 86c796ed89..0000000000 --- a/packages/agentic/native-core/macos/components/Callout/shared/FRNCallout.h +++ /dev/null @@ -1,14 +0,0 @@ -// -// FRNCallout.h -// Pods -// -// Created by Patrick Boyd on 9/24/24. -// -// Created as a dummy file to enable importing FRNNativeCore-Swift.h and invoking Swift functions from Obj-C -// - -#ifndef FRNCallout_h -#define FRNCallout_h - - -#endif /* FRNCallout_h */ diff --git a/packages/agentic/native-core/macos/shared/FRNNativeCore.h b/packages/agentic/native-core/macos/shared/FRNNativeCore.h new file mode 100644 index 0000000000..8c039ee640 --- /dev/null +++ b/packages/agentic/native-core/macos/shared/FRNNativeCore.h @@ -0,0 +1,2 @@ +// The generated FRNNativeCore-Swift.h imports this module-named interoperability header. +#pragma once diff --git a/packages/agentic/native-core/package.json b/packages/agentic/native-core/package.json index b31e76f650..f73334bcbc 100644 --- a/packages/agentic/native-core/package.json +++ b/packages/agentic/native-core/package.json @@ -80,7 +80,8 @@ "format": "fluentui-scripts format", "lint": "fluentui-scripts lint", "prebuild": "yarn codegen:windows", - "test": "yarn build && node --test tests/entrypoints.test.mjs tests/native-ownership.test.mjs && fluentui-scripts jest", + "test": "yarn build && yarn test:stories && node --test tests/entrypoints.test.mjs tests/native-ownership.test.mjs && fluentui-scripts jest", + "test:stories": "tsc -p tsconfig.stories.json", "update-snapshots": "fluentui-scripts jest -u" }, "dependencies": { @@ -90,6 +91,7 @@ "devDependencies": { "@babel/core": "catalog:", "@fluentui-react-native/scripts": "workspace:*", + "@fluentui-react-native/storybook-desktop": "workspace:*", "@office-iss/react-native-win32": "^0.81.8", "@react-native-community/cli": "^20.0.0", "@react-native-community/cli-platform-android": "^20.0.0", diff --git a/packages/agentic/native-core/src/legacy/callout/Callout.stories.tsx b/packages/agentic/native-core/src/legacy/callout/Callout.stories.tsx index 6ae0691aaf..c139f7a9fb 100644 --- a/packages/agentic/native-core/src/legacy/callout/Callout.stories.tsx +++ b/packages/agentic/native-core/src/legacy/callout/Callout.stories.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; +import type { WdioStory } from '@fluentui-react-native/storybook-desktop/testing'; import type { Meta, StoryObj } from '@storybook/react-native'; import { Callout } from './Callout'; @@ -48,6 +49,11 @@ const CalloutExample = ({ defaultVisible = false, onDismiss, onShow, showWindowC return ( + + + Native window: {status} + + {visible ? 'Close callout' : 'Open callout'} - - Native window: {status} - {visible && ( @@ -177,10 +180,37 @@ const meta: Meta = { export default meta; -type Story = StoryObj; +type Story = WdioStory>; export const Default: Story = { + tags: ['desktop-e2e'], render: (args) => , + wdio: { + 'macOS opens, dismisses, and recreates a native popup window': async ({ browser, expect, platform, skip }) => { + if (platform !== 'macos') { + skip('This case verifies the AppKit popup-window lifecycle.'); + return; + } + const features = browser.capabilities['furn:features']; + if (!features?.physicalClick) { + skip('Popup lifecycle qualification requires physical pointer input.'); + return; + } + for (let attempt = 0; attempt < 2; attempt++) { + await expect(await browser.$('~agentic-storybook-callout-status')).toHaveText('Native window: Shown'); + expect(await browser.getWindowHandles()).toHaveLength(2); + await (await browser.$('~agentic-storybook-callout-status')).click(); + await browser.waitUntil(async () => (await browser.getWindowHandles()).length === 1, { + timeout: 5000, + timeoutMsg: 'Expected dismissal to remove the native Callout window.', + }); + await expect(await browser.$('~agentic-storybook-callout-status')).toHaveText('Native window: Dismissed'); + if (attempt === 0) { + await (await browser.$('~agentic-storybook-callout-trigger')).click(); + } + } + }, + }, }; export const Placement: Story = { @@ -252,7 +282,7 @@ const styles = StyleSheet.create({ }, status: { color: '#616161', - marginTop: 12, + marginBottom: 12, }, story: { alignItems: 'center', diff --git a/packages/agentic/native-core/tests/native-ownership.test.mjs b/packages/agentic/native-core/tests/native-ownership.test.mjs index 12a85727fc..ceb5ab99ce 100644 --- a/packages/agentic/native-core/tests/native-ownership.test.mjs +++ b/packages/agentic/native-core/tests/native-ownership.test.mjs @@ -47,6 +47,19 @@ test('the shared macOS pod includes both components and retains both renderer ad } }); +test('macOS Swift interoperability uses the consolidated pod module name', async () => { + const podspec = await readFile(new URL('FRNNativeCore.podspec', packageRoot), 'utf8'); + const moduleName = podspec.match(/s\.module_name\s*=\s*'([^']+)'/)?.[1]; + assert.equal(moduleName, 'FRNNativeCore'); + await readFile(new URL(`macos/shared/${moduleName}.h`, packageRoot), 'utf8'); + + for (const adapter of ['fabric/RCTCalloutComponentView.mm', 'paper/FRNCalloutManager.m']) { + const source = await readFile(new URL(`macos/components/Callout/${adapter}`, packageRoot), 'utf8'); + assert.ok(source.includes(`#import "${moduleName}-Swift.h"`)); + assert.doesNotMatch(source, /FRNCallout-Swift\.h/); + } +}); + for (const shim of ['callout', 'focus-zone']) { test(`${shim} is a JS-only compatibility shim with no duplicate native ownership`, async () => { const root = new URL(`../../shim/${shim}/`, packageRoot); diff --git a/packages/agentic/native-core/tsconfig.stories.json b/packages/agentic/native-core/tsconfig.stories.json new file mode 100644 index 0000000000..40b8e99540 --- /dev/null +++ b/packages/agentic/native-core/tsconfig.stories.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "composite": false, + "noImplicitAny": true, + "noEmit": true, + "tsBuildInfoFile": ".cache/tsconfig.stories.tsbuildinfo" + }, + "include": ["src/legacy/callout/Callout.stories.tsx"], + "exclude": [], + "references": [ + { + "path": "./tsconfig.json" + }, + { + "path": "../storybook-desktop/tsconfig.json" + } + ] +} diff --git a/yarn.lock b/yarn.lock index 3273416e4e..3f73143881 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4519,6 +4519,7 @@ __metadata: "@fluentui-react-native/framework-base": "workspace:*" "@fluentui-react-native/interactive-hooks": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" + "@fluentui-react-native/storybook-desktop": "workspace:*" "@office-iss/react-native-win32": "npm:^0.81.8" "@react-native-community/cli": "npm:^20.0.0" "@react-native-community/cli-platform-android": "npm:^20.0.0" From cba3377f4fce1ed187edf141e081f9a8ca472675 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 2 Oct 2026 16:03:05 -0700 Subject: [PATCH 5/5] fix tsconfig configuration --- packages/agentic/native-core/tsconfig.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/agentic/native-core/tsconfig.json b/packages/agentic/native-core/tsconfig.json index bd2b34cb96..b8fd9ae534 100644 --- a/packages/agentic/native-core/tsconfig.json +++ b/packages/agentic/native-core/tsconfig.json @@ -17,6 +17,9 @@ }, { "path": "../../../scripts/tsconfig.json" + }, + { + "path": "../storybook-desktop/tsconfig.json" } ] }