# @cdx-ui/components

Styled, theme-aware UI components for the Forge Design System.

Built on top of [`@cdx-ui/primitives`](../primitives/), [`@cdx-ui/utils`](../utils/), and [`@cdx-ui/icons`](../icons/), styled via [Uniwind](https://uniwind.dev) + [CVA](https://cva.style). Design tokens from [`@cdx-ui/styles`](../styles/) are consumed at the app level (not a direct package dependency).

## Installation

```bash
pnpm add @cdx-ui/components
```

### Peer dependencies

- `react` ^18.2.0 or ^19.0.0
- `react-native` >= 0.76.0 _(optional — for native targets)_
- `react-native-web` >= 0.19.0 _(optional — for web targets)_
- `react-native-safe-area-context` >= 4.0.0 — required for `SafeAreaView` and `useSafeAreaInsets` re-exports
- `react-native-reanimated` >= 4.0.0 _(optional — required for `BottomSheet`, `Skeleton`, `Carousel`, `Dialog`, and `AlertDialog`)_
- `react-native-worklets` >= 0.4.0 _(optional — required alongside `react-native-reanimated` for animated components such as `Dialog`)_
- `react-native-gesture-handler` >= 2.0.0 _(optional — required for `Dialog`/`AlertDialog` swipe-to-dismiss)_
- `@shopify/flash-list` >= 2.0.0 _(optional — required for `VirtualizedList`)_

> **Note:** `uniwind` (1.10.x) is a direct dependency — it is bundled automatically and does not need to be installed separately.

## Usage

```tsx
import { Button } from '@cdx-ui/components';

export function Example() {
  return (
    <Button variant="solid" color="action" size="default" onPress={() => console.log('pressed')}>
      <Button.Label>Get Started</Button.Label>
    </Button>
  );
}
```

Component stories live in [`apps/storybook`](../../apps/storybook/). See the full [component reference](../../docs/README.md#components) for per-component docs.

### Components

Alert, AlertDialog, Avatar, Badge, BottomSheet, Button, Card, Carousel, Checkbox, Chip, CurrencyInput, Dialog, Divider, Field, Form, Heading, HStack / VStack, Icon, IconButton, Image, Input, InsuranceDisclosure, Link, ListItem, OtpInput, ProgressBar, ProgressSegmented, QuickActionButton, Radio, ScopedTheme, Select, Skeleton, Slider, Switch, Text, Textarea, Tile, Toast, VirtualizedList.

> `Box` is exported but deprecated — use React Native's `View` directly.

### Hooks and navigation

| Export                             | Description                                                            |
| ---------------------------------- | ---------------------------------------------------------------------- |
| `useForgeBottomTabScreenOptions`   | Generates Forge-themed screen options for React Navigation bottom tabs |
| `mergeForgeBottomTabScreenOptions` | Merges Forge bottom-tab options with consumer overrides                |
| `forgeTabIcon`                     | Creates a tab icon descriptor for native bottom tabs                   |

### Metro configuration helper

The package ships a `withForgeMetroConfig` helper that wraps your Metro config with Forge UI's styling-layer setup. This abstracts the underlying Uniwind configuration so consuming Metro configs stay stable if the styling layer changes.

```js
const { withForgeMetroConfig } = require('@cdx-ui/components/metro');

module.exports = withForgeMetroConfig(config, {
  cssEntryFile: './global.css',
  generatedTypesFile: './uniwind-types.d.ts', // optional
});
```

`withForgeMetroConfig` must be the **outermost** wrapper if you compose multiple Metro config helpers.

### React Native re-exports

For convenience, the package re-exports several core RN components and hooks with Uniwind `className` support:

| Export                 | Source                           |
| ---------------------- | -------------------------------- |
| `View`                 | `react-native`                   |
| `ScrollView`           | `react-native`                   |
| `KeyboardAvoidingView` | `react-native`                   |
| `SafeAreaView`         | `react-native-safe-area-context` |
| `useSafeAreaInsets`    | `react-native-safe-area-context` |

## Figma Code Connect

Template files in [`src/figma/`](./src/figma/) map Figma component variants to production Forge UI snippets shown in Figma Dev Mode. These files are excluded from the npm tarball (`!src/figma` in `files`) and published to Figma via CI on pushes to `main`.

See the **[Code Connect authoring guide](../../docs/internal/practices/code-connect.md)** for conventions, property mapping patterns, and local workflow.

## Testing

Tests live in [`__tests__/`](./__tests__/). **Jest** uses the repo-root **`jest.config.js`** with **five projects**: **`rntl`** (jest-expo native + **`@testing-library/react-native`**) for `*.test.tsx`, **`axe`** (jest-expo web + jsdom + **`@testing-library/react`** + **`jest-axe`**) for `*.axe.test.tsx`, **`utils`** (**`@cdx-ui/utils`** co-located tests), **`styles`** (**`@cdx-ui/styles`** jest-expo native), and **`icons`** (**`@cdx-ui/icons`** jest-expo native). The first two target `packages/components/__tests__/`.

```bash
# From monorepo root
pnpm nx run @cdx-ui/components:test
# or
pnpm test:all
```

Production types use `tsconfig.json`; tests use `tsconfig.test.json`.

**Authoring:** See **[docs/internal/testing.md](../../docs/internal/testing.md)** (RNTL vs DOM, `fireEvent.press` vs `fireEvent.click`, file naming).

**A11y-only ad-hoc** (from `packages/components`):  
`pnpm exec jest --config ../../jest.config.js --testNamePattern="a11y"`
