|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +This is the **FluentUI React Native** repository, a monorepo containing React Native components that implement Microsoft's Fluent Design System. The repository supports multiple platforms including iOS, Android, macOS, Windows, and Win32. |
| 8 | + |
| 9 | +## Repository Architecture |
| 10 | + |
| 11 | +### High-Level Structure |
| 12 | +``` |
| 13 | +/apps/ - Demo and test applications |
| 14 | + /fluent-tester/ - Main test app for component development |
| 15 | + /E2E/ - End-to-end testing setup using Appium/WebDriverIO |
| 16 | + /win32/ - Win32-specific test app |
| 17 | + /component-generator/ - Tool to generate new components |
| 18 | +/packages/ - Core library packages |
| 19 | + /components/ - UI component implementations (Button, Checkbox, Avatar, etc.) |
| 20 | + /framework/ - Core theming and composition framework |
| 21 | + /composition/ - Component composition factory (current approach) |
| 22 | + /theme/ - Theme system |
| 23 | + /use-tokens/ - Token-based styling hooks |
| 24 | + /use-slots/ - Slot-based component composition |
| 25 | + /theming/ - Theme definitions for different platforms |
| 26 | + /android-theme/ |
| 27 | + /apple-theme/ |
| 28 | + /default-theme/ |
| 29 | + /win32-theme/ |
| 30 | + /experimental/ - Components under active development |
| 31 | + /deprecated/ - Old framework code (foundation-compose, foundation-composable) |
| 32 | + /utils/ - Shared utilities and tools |
| 33 | +/scripts/ - Build and development scripts (fluentui-scripts CLI) |
| 34 | +/docs/ - Component and theming documentation |
| 35 | +``` |
| 36 | + |
| 37 | +### Key Framework Concepts |
| 38 | + |
| 39 | +**Composition Framework**: The repository uses `@fluentui-react-native/composition` (located at `packages/framework/composition/`) for building components. This is the current approach and is simpler than the older foundation-compose/foundation-composable frameworks in `/deprecated/`. |
| 40 | + |
| 41 | +**Slots**: The slot pattern is used to compose higher-order components. A slot represents an inner component (actual entry in the render tree). For example, a Button might have slots for `root`, `icon`, and `content`. This allows advanced customization scenarios. Components wrapping a single native component typically have one slot. |
| 42 | + |
| 43 | +**Tokens**: Design tokens handle styling and customization. Tokens are design-time values set via theme or component customization (e.g., "brandColor"). Tokens can also be props (specified via "TokensThatAreAlsoProps"). This system enables simpler customization and better memoization. |
| 44 | + |
| 45 | +**Platform-Specific Files**: Components use platform-specific files with extensions like `.ios.ts`, `.android.ts`, `.win32.ts`, `.macos.ts` for platform-specific implementations. |
| 46 | + |
| 47 | +**Legacy vs V1**: Many components have both legacy and V1 implementations (e.g., `Button` and `ButtonV1`). The V1 versions use the newer composition framework and are preferred. |
| 48 | + |
| 49 | +## Build System & Commands |
| 50 | + |
| 51 | +The project uses **Yarn 4** (Berry) in **pnpm mode** with **Lage** as the task runner for orchestrating builds across the monorepo. The pnpm mode provides better disk space efficiency and stricter dependency management. |
| 52 | + |
| 53 | +### Primary Commands |
| 54 | +```bash |
| 55 | +yarn build # TypeScript build for all packages (outputs to lib/ and lib-commonjs/) |
| 56 | +yarn test # Build, lint, and run tests across all packages |
| 57 | +yarn lint # ESLint across all packages |
| 58 | +yarn bundle # Bundle all packages |
| 59 | +yarn buildci # Full CI pipeline: build + test + lint + bundle + depcheck + check-publishing |
| 60 | +yarn clean # Clean build artifacts |
| 61 | +``` |
| 62 | + |
| 63 | +### Development Commands |
| 64 | +```bash |
| 65 | +yarn prettier-fix # Format code with Prettier |
| 66 | +yarn depcheck # Check for unused dependencies across packages |
| 67 | +yarn depcheck-fix # Fix depcheck issues automatically |
| 68 | +yarn align-deps # Align React Native dependencies using @rnx-kit/align-deps |
| 69 | +yarn change # Generate Beachball change files (required before PR merge) |
| 70 | +yarn checkchange # Verify change files exist for modified packages |
| 71 | +``` |
| 72 | + |
| 73 | +### Lage Configuration |
| 74 | +The build pipeline is defined in `lage.config.js`: |
| 75 | +- Tasks have dependency ordering (e.g., `test` depends on `build`) |
| 76 | +- Lage uses caching to avoid redundant steps |
| 77 | +- Add `--no-cache` to bypass caching |
| 78 | +- Add `--verbose` for detailed output |
| 79 | + |
| 80 | +### Package-Level Commands |
| 81 | +Individual packages use `fluentui-scripts` (in `/scripts/`) which provides: |
| 82 | +- `yarn build` - TypeScript compilation to `lib/` (ESM) and `lib-commonjs/` (CJS) |
| 83 | + - The build script automatically sets `--moduleResolution` to match `--module` for TypeScript 5.8+ compatibility |
| 84 | + - ESM builds use `--module esnext --moduleResolution bundler` |
| 85 | + - CJS builds use `--module node16 --moduleResolution node16` |
| 86 | +- `yarn lint` - ESLint |
| 87 | +- `yarn lint-package` - Lint package configuration (includes align-deps and depcheck) |
| 88 | + - Use `--fix` flag to automatically fix issues |
| 89 | + - Validates dependencies, scripts, entry points, and build configuration |
| 90 | +- `yarn test` - Jest tests (where applicable) |
| 91 | +- `yarn depcheck` - Check for unused dependencies |
| 92 | +- `yarn prettier` - Check code formatting |
| 93 | +- `yarn prettier-fix` - Fix code formatting |
| 94 | + |
| 95 | +## TypeScript Configuration |
| 96 | + |
| 97 | +The repository uses **TypeScript 5.8+** with **@typescript/native-preview** for improved performance and React Native compatibility. The native preview is automatically added to packages with a `tsconfig.json` via dynamic package extensions. |
| 98 | + |
| 99 | +### Key TypeScript Settings |
| 100 | +- Base configuration in `/scripts/configs/tsconfig.json` |
| 101 | +- Module system: `node16` with matching `moduleResolution: node16` |
| 102 | +- Target: `es2022` |
| 103 | +- Strict mode enabled (with some exceptions for legacy code compatibility) |
| 104 | +- **TypeScript Native Preview**: Packages automatically receive `@typescript/native-preview` as a development dependency |
| 105 | + |
| 106 | +### TypeScript 5.8+ Compatibility Notes |
| 107 | +- The `suppressImplicitAnyIndexErrors` option has been removed (deprecated in TS 5.8+) |
| 108 | +- Module resolution must match module format when using Node16 resolution |
| 109 | +- Stricter type checking for platform values (e.g., `Platform.OS` doesn't include 'win32' in React Native types, but react-native-windows does support it at runtime) |
| 110 | +- TypeScript native preview provides better performance for large React Native codebases |
| 111 | + |
| 112 | +### Framework Type System |
| 113 | +The composition framework uses precise types for better type safety: |
| 114 | +- **`SlotFn<TProps>`**: Slot functions return `React.ReactElement | null` (not `ReactNode`) |
| 115 | + - This reflects the actual behavior: slots always return elements via staged render or `React.createElement` |
| 116 | + - Provides better type inference when accessing slot props (e.g., `Slots.root({}).props`) |
| 117 | +- **`FinalRender<TProps>`**: Final render functions in staged components return `JSX.Element | null` |
| 118 | + - Used in composition framework's `useRender` functions |
| 119 | + - Ensures type compatibility between staged components and the composition system |
| 120 | + |
| 121 | +## Development Workflow |
| 122 | + |
| 123 | +### Setting Up Development Environment |
| 124 | +1. Clone repository |
| 125 | +2. Run `yarn` to install dependencies |
| 126 | +3. Run `yarn build` to build all packages |
| 127 | +4. Launch FluentUI Tester app for component testing (see `/apps/fluent-tester/README.md`) |
| 128 | + |
| 129 | +### Component Development |
| 130 | + |
| 131 | +**Component Location**: Components are in `/packages/components/` (stable) or `/packages/experimental/` (under development). |
| 132 | + |
| 133 | +**Component Structure**: Each component typically has: |
| 134 | +- `package.json` - Package definition with workspace dependencies |
| 135 | +- `src/index.ts` - Main export file |
| 136 | +- `src/<Component>.tsx` - Component implementation (requires `/** @jsxImportSource @fluentui-react-native/framework-base */` pragma) |
| 137 | +- `src/<Component>.types.ts` - TypeScript type definitions |
| 138 | +- `src/<Component>.styling.ts` - Styling and token definitions |
| 139 | +- `src/<Component>.<platform>.ts` - Platform-specific implementations |
| 140 | +- `SPEC.md` - Component specification and usage documentation |
| 141 | +- `MIGRATION.md` - Migration guide (for V1 components) |
| 142 | +- `tsconfig.json`, `babel.config.js`, `jest.config.js`, `eslint.config.js` |
| 143 | + |
| 144 | +**Using Composition Framework**: Use `@fluentui-react-native/composition` for new components. For simpler components without slots/tokens, use the `stagedComponent` pattern from `@fluentui-react-native/use-slot`. |
| 145 | + |
| 146 | +**JSX Runtime**: All components use the modern automatic JSX runtime: |
| 147 | +- Add `/** @jsxImportSource @fluentui-react-native/framework-base */` at the top of `.tsx` files |
| 148 | +- The custom jsx-runtime intercepts JSX calls to optimize slot rendering |
| 149 | +- No need to import `withSlots` - it's handled automatically by the runtime |
| 150 | +- Components using React Fragments (`<>...</>`) work automatically (Fragment is re-exported from the jsx-runtime) |
| 151 | +- Packages using the jsx-runtime need `@fluentui-react-native/framework-base` in `devDependencies` |
| 152 | + |
| 153 | +**TypeScript Patterns**: |
| 154 | +- Slot functions automatically return `React.ReactElement`, so you can access `.props` directly without type assertions |
| 155 | +- When checking for win32 platform: `Platform.OS === ('win32' as any)` - TypeScript doesn't recognize 'win32' but react-native-windows supports it |
| 156 | +- Final render functions should return `FinalRender<TProps>` with children as rest parameters: `(props: TProps, ...children: React.ReactNode[])` |
| 157 | + |
| 158 | +**Native Modules**: Components with native code (iOS/Android/Windows): |
| 159 | +- Typically have one root slot wrapping the native component |
| 160 | +- Use `codegenNativeComponent` for new architecture compatibility |
| 161 | +- May use `constantsToExport` for default values from native side |
| 162 | +- iOS/macOS: Include `.podspec` files |
| 163 | +- Must be added to FluentTester's Podfile (transitive dependencies aren't autolinked) |
| 164 | + |
| 165 | +### Creating a New Component |
| 166 | + |
| 167 | +1. Create directory: `/packages/components/<ComponentName>` or `/packages/experimental/<ComponentName>` |
| 168 | +2. Copy structure from existing component (e.g., Shimmer, Button) |
| 169 | +3. Update `package.json` with correct name and dependencies (use `workspace:*` for internal packages) |
| 170 | +4. Create source files in `src/` |
| 171 | +5. Add test page to FluentTester at `/apps/fluent-tester/src/TestComponents/<ComponentName>/` |
| 172 | +6. Register test page in `testPages.tsx` and platform-specific `testPages.<platform>.tsx` |
| 173 | +7. Add E2E tests (see E2E Testing section) |
| 174 | +8. Run `yarn` and `yarn build` from root |
| 175 | +9. For Apple platforms: run `pod install` in test app directories |
| 176 | + |
| 177 | +### Theming |
| 178 | + |
| 179 | +Platform-specific themes are in `/packages/theming/`: |
| 180 | +- `android-theme/` - Android theming |
| 181 | +- `apple-theme/` - iOS and macOS theming |
| 182 | +- `win32-theme/` - Win32 theming |
| 183 | +- `default-theme/` - Cross-platform defaults |
| 184 | +- `theme-tokens/` - Token definitions |
| 185 | +- `theme-types/` - TypeScript types for themes |
| 186 | + |
| 187 | +Components require `ThemeProvider` from `@fluentui-react-native/theme` to work properly. |
| 188 | + |
| 189 | +### Testing |
| 190 | + |
| 191 | +**Manual Testing**: Use FluentUI Tester app (`/apps/fluent-tester/`) for interactive component testing. Test pages are in `/apps/fluent-tester/src/TestComponents/`. |
| 192 | + |
| 193 | +**E2E Testing**: Required for all new components. Uses Appium + WebDriverIO. |
| 194 | +- E2E tests live in `/apps/E2E/src/<ComponentName>/` |
| 195 | +- Each component needs: |
| 196 | + - Page Object (`<Component>PageObject.<platform>.ts`) - Interface to interact with test page |
| 197 | + - Spec Document (`<Component>Spec.<platform>.ts`) - Jasmine test cases |
| 198 | + - Constants file in test component (`/apps/fluent-tester/src/TestComponents/<Component>/consts.ts`) |
| 199 | +- Test pages must include: |
| 200 | + - `testID` on first section matching page object's `_pageName` |
| 201 | + - Optional `e2eSections` prop for dedicated E2E test elements |
| 202 | +- Run E2E tests: `yarn e2etest:<platform>` from `/apps/E2E/` |
| 203 | + |
| 204 | +**Unit Tests**: Component-specific Jest tests where present, typically in `src/` directories. |
| 205 | + |
| 206 | +### Platform-Specific Development |
| 207 | + |
| 208 | +**iOS/macOS**: |
| 209 | +- May wrap native controls from FluentUI Apple |
| 210 | +- Requires `.podspec` files for native modules |
| 211 | +- Run `pod install` after adding dependencies |
| 212 | + |
| 213 | +**Android**: |
| 214 | +- Platform-specific styling and tokens |
| 215 | +- Uses `accessibilityLabel` for E2E selectors (other platforms use `testID`) |
| 216 | + |
| 217 | +**Win32**: |
| 218 | +- Separate test app at `/apps/win32/` |
| 219 | +- Uses WinAppDriver for E2E testing |
| 220 | + |
| 221 | +**Windows (UWP)**: |
| 222 | +- Separate test app configuration |
| 223 | +- Legacy support |
| 224 | + |
| 225 | +## Version Management |
| 226 | + |
| 227 | +**Beachball**: Used for change logs and versioning. |
| 228 | +- Run `yarn change` to create change files when modifying packages |
| 229 | +- Change files are required before merging PRs (`yarn checkchange` validates) |
| 230 | +- Beachball config in `beachball.config.js` |
| 231 | +- Major versions are disallowed (`disallowedChangeTypes: ['major']`) |
| 232 | +- On publish, `onPublish` field in `package.json` gets merged into package |
| 233 | + |
| 234 | +## Important Notes |
| 235 | + |
| 236 | +- This is an **alpha-stage** library under active development |
| 237 | +- **Requires TypeScript 5.8+** with `@typescript/native-preview` for proper type checking and module resolution |
| 238 | +- **Uses Yarn 4 in pnpm mode** for dependency management (configured in `.yarnrc.yml`) |
| 239 | +- **Uses modern automatic JSX runtime** - all components should use `@jsxImportSource @fluentui-react-native/framework-base` |
| 240 | +- **Dynamic package extensions**: Common dev dependencies (TypeScript, Jest, ESLint, Prettier) are automatically added via `scripts/dynamic.extensions.mjs` |
| 241 | +- **Integrated linting**: `yarn lint-package` now includes align-deps and depcheck validation |
| 242 | +- Follow existing component patterns for consistency |
| 243 | +- Test components using FluentUI Tester app before submitting PRs |
| 244 | +- Platform differences should be documented in component `SPEC.md` files |
| 245 | +- Use the newer composition framework (`@fluentui-react-native/composition`) for new components, not the deprecated foundation frameworks |
| 246 | +- When importing V1 components, consider aliasing: `import { ButtonV1 as Button }` |
| 247 | +- Slot functions return `React.ReactElement` - you can safely access `.props` without type assertions |
0 commit comments