npm package: @synexusjs/react
Description: Shared React UI primitives, hooks, and utilities extracted from the CMPC Orchestration client.
Latest version: 0.2.0

# @synexusjs/react

Shared React UI primitives, hooks, and utilities extracted from the CMPC Orchestration client.

## Exports

### Main entry (`@synexusjs/react`)

| Category      | Exports                                                              |
| ------------- | -------------------------------------------------------------------- |
| **Utils**     | `cn`, `readLocalStorage`, `writeLocalStorage`, `removeLocalStorage`, `buildPaginationTokens`, `resolveTotalPages` |
| **Hooks**     | `useDebounce`, `useDisclosure`, `useEventListener`, `useLockBodyScroll`, `useFocusTrap`, `usePageTitle` |
| **Primitives**| `Button`, `Badge`, `LiveIndicator`                                   |
| **Forms**     | `Input`, `Textarea`, `Select`                                        |
| **Feedback**  | `ContentState`, `Tooltip`                                            |
| **Data**      | `Table`, `TableHeader`, `TableBody`, `TableHead`, `TableRow`, `TableCell`, `AnimatedTableBody`, `AnimatedTableRow`, `JsonBlock` |
| **Navigation**| `Tabs`                                                               |
| **Layout**    | `Card`, `CardHeader`, `CardContent`, `CardFooter`                    |
| **Overlays**  | `Modal`                                                              |

### Animations entry (`@synexusjs/react/animations`)

`tableStateMotion`, `tableContainerMotion`, `tableRowsMotion`, `tableRowMotion`, `tableLoadingMotion`

> Requires `motion` as a peer dependency.

## Progressive Adoption

Replace imports one module at a time. No big-bang migration required.

```diff
- import { Button } from '@/shared/ui/Button';
+ import { Button } from '@synexusjs/react';

- import { cn } from '@/shared/utils/cn';
+ import { cn } from '@synexusjs/react';

- import { useDebounce } from '@/shared/hooks/use-debounce';
+ import { useDebounce } from '@synexusjs/react';

- import { tableRowsMotion, tableRowMotion } from '@/shared/animations/table.animations';
+ import { tableRowsMotion, tableRowMotion } from '@synexusjs/react/animations';
```

### Migration order (recommended)

1. **Utils first** (`cn`, `local-storage`, `pagination`) — zero UI risk, pure functions
2. **Hooks** — no rendering changes, behavioral only
3. **Primitives** (`Button`, `Badge`, `LiveIndicator`) — leaf components, no children dependencies
4. **Forms** (`Input`, `Textarea`, `Select`) — isolated form elements
5. **Feedback + Data** (`ContentState`, `Tooltip`, `Table`, `Tabs`, `JsonBlock`) — composite but self-contained
6. **Layout + Overlays** (`Card`, `Modal`) — may have more integration points

### Validation per step

After each group, run:

```bash
cd client && npx tsc --noEmit && npm run build
```

## Peer Dependencies

- `react` >= 19.0.0
- `react-dom` >= 19.0.0
- `tailwindcss` >= 4.0.0

## Optional Peer Dependencies

- `lucide-react` — icons in Button, Modal close button
- `motion` — only needed if using `AnimatedTable*` components or `@synexusjs/react/animations`

## Theming

Components use CSS custom properties from the host app's theme:

- `--org-primary-color` / `--org-primary-hover` / `--org-primary-active`
- `--org-border-radius`

These must be defined in the consuming app's CSS. Components fall back to neutral Tailwind colors when custom properties are not set.

## Development

```bash
# TypeScript check
cd packages/synexusjs-react && npx tsc --noEmit

# Build (when publishing is needed)
cd packages/synexusjs-react && npx vite build
```

## Re-running the migration

```bash
# Analysis only (no file changes)
npx tsx scripts/migrate-to-package.ts

# Copy files + rewrite imports
npx tsx scripts/migrate-to-package.ts --copy

# Dry run (prints what would happen)
npx tsx scripts/migrate-to-package.ts --dry-run
```