import { pageMetadata } from "@/lib/page-metadata"
export const metadata = pageMetadata("docs/code-export")

# Code Export

Export generated UI as standalone code for your framework.

## Overview

While json-render is designed for dynamic rendering, you can export generated UI as static code. The code generation is intentionally project-specific so you have full control over:

- Component templates (standalone, no json-render dependencies)
- Package.json and project structure
- Framework-specific patterns (Next.js, Remix, etc.)
- How data is passed to components

## Architecture

Code export is split into two parts:

### 1. @json-render/codegen (utilities)

Framework-agnostic utilities for building code generators:

```typescript
import {
  traverseSpec,          // Walk the UI spec
  collectUsedComponents, // Get all component types used
  collectStatePaths,      // Get all data binding paths
  collectActions,        // Get all action names
  serializeProps,        // Convert props to JSX string
} from '@json-render/codegen';
```

### 2. Your Project (generator)

Custom code generator specific to your project and framework:

```typescript
// lib/codegen/generator.ts
import { collectUsedComponents, serializeProps } from '@json-render/codegen';

export function generateNextJSProject(spec: Spec): GeneratedFile[] {
  const components = collectUsedComponents(spec);
  
  return [
    { path: 'package.json', content: '...' },
    { path: 'app/page.tsx', content: '...' },
    // ... component files
  ];
}
```

## Example: Next.js Export

See the dashboard example for a complete implementation that exports:

- `package.json` - Dependencies and scripts
- `tsconfig.json` - TypeScript config
- `next.config.js` - Next.js config
- `app/layout.tsx` - Root layout
- `app/globals.css` - Global styles
- `app/page.tsx` - Generated page with data
- `components/ui/*.tsx` - Standalone components

## Standalone Components

The exported components are standalone with no json-render dependencies. They receive data as props instead of using hooks:

```tsx
// Generated component (standalone)
interface MetricProps {
  label: string;
  statePath: string;
  data?: Record<string, unknown>;
}

export function Metric({ label, statePath, data }: MetricProps) {
  const value = data ? getByPath(data, statePath) : undefined;
  return (
    <div>
      <span>{label}</span>
      <span>{formatValue(value)}</span>
    </div>
  );
}
```

## Using the Utilities

### traverseSpec

```typescript
import { traverseSpec } from '@json-render/codegen';

traverseSpec(spec, (element, key, depth, parent) => {
  console.log(' '.repeat(depth * 2) + `${key}: ${element.type}`);
});
```

### collectUsedComponents

```typescript
import { collectUsedComponents } from '@json-render/codegen';

const components = collectUsedComponents(spec);
// Set { 'Card', 'Metric', 'Chart', 'Table' }

// Generate only the needed component files
for (const component of components) {
  files.push({
    path: `components/ui/${component.toLowerCase()}.tsx`,
    content: componentTemplates[component],
  });
}
```

### serializeProps

```typescript
import { serializeProps } from '@json-render/codegen';

const propsStr = serializeProps({
  title: 'Dashboard',
  columns: 3,
  disabled: true,
});
// 'title="Dashboard" columns={3} disabled'
```

## Try It

Run the dashboard example and click "Export Project" to see code generation in action:

```bash
cd examples/dashboard
pnpm dev
# Open http://dashboard-demo.json-render.localhost:1355
# Generate a widget, then click "Export Project"
```
