# OneX Theme API Reference

**Version**: 1.0.0
**Package**: `@onex/core`
**Status**: Public API

---

## Overview

This document defines the **public API contract** for OneX theme developers. All types and interfaces marked with `@public` are stable and follow semantic versioning.

### Stability Guarantee

- ✅ **Public API** (`@public` tag): Stable, semantic versioning applies
- ⚠️ **Internal API** (no tag): May change without notice, do not use

### Breaking Change Policy

- **Major version** (2.0.0): Breaking changes to public API
- **Minor version** (1.1.0): New features, backward compatible
- **Patch version** (1.0.1): Bug fixes, backward compatible

---

## Public API

### Core Types

All types are imported from `@onex/core`:

```typescript
import type {
  // Theme Contract
  ThemeManifest,
  ThemeModule,
  ThemeConfig,

  // Section Types
  SectionComponentProps,
  SectionInstance,
  SectionSchema,
  TemplateDefinition,

  // Component Types
  ComponentInstance,

  // Block Types
  BlockInstance,

  // Validation
  ValidationResult,
  ValidationError,
  ValidationWarning,
} from "@onex/core";
```

---

## Theme Manifest

**Location**: `packages/core/src/types/theme.ts`
**Tag**: `@public`

The manifest is the primary contract between your theme and the OneX platform.

### Interface

```typescript
interface ThemeManifest {
  /** Unique theme identifier (lowercase, kebab-case) */
  id: string;

  /** Human-readable theme name */
  name: string;

  /** Semantic version (e.g., "1.0.0") */
  version: string;

  /** Theme description */
  description?: string;

  /** Theme author information */
  author: {
    name: string;
    email?: string;
    url?: string;
  };

  /** OneX engine version compatibility (e.g., "^1.0.0") */
  engine: string;

  /** Required peer dependencies */
  peerDependencies: {
    react: string;
    "react-dom": string;
    "@onex/core"?: string;
  };

  /** Available sections in this theme */
  sections: string[];

  /** Theme configuration (colors, typography, etc.) */
  config: ThemeConfig;

  /** Entry points for the theme bundle */
  exports: {
    main: string;
    types?: string;
  };

  /** Optional theme preview/screenshot */
  preview?: {
    thumbnail?: string;
    screenshots?: string[];
  };

  /** Optional license information */
  license?: string;

  /** Optional homepage/repository */
  repository?: string;

  /** Optional tags for categorization */
  tags?: string[];
}
```

### Example

```typescript
export const manifest: ThemeManifest = {
  id: "my-awesome-theme",
  name: "My Awesome Theme",
  version: "1.0.0",
  description: "A beautiful, modern theme for e-commerce",
  author: {
    name: "Your Name",
    email: "you@example.com",
    url: "https://yoursite.com",
  },
  engine: "^1.0.0",
  peerDependencies: {
    react: "^19.0.0",
    "react-dom": "^19.0.0",
    "@onex/core": "^1.0.0",
  },
  sections: ["hero-default", "hero-minimal", "footer-default"],
  config: themeConfig,
  exports: {
    main: "./dist/index.mjs",
    types: "./dist/index.d.ts",
  },
  tags: ["e-commerce", "minimal", "modern"],
  license: "MIT",
};
```

### Validation Rules

- `id`: Must be lowercase, kebab-case, 3-50 characters
- `version`: Must follow semver (e.g., "1.0.0")
- `engine`: Must be valid semver range (e.g., "^1.0.0", ">=1.0.0 <2.0.0")
- `sections`: Must match exported section component keys

---

## Theme Module

**Tag**: `@public`

The structure your theme bundle must export.

### Interface

```typescript
interface ThemeModule {
  /** Theme manifest */
  manifest: ThemeManifest;

  /** Section components registry */
  sections: Record<string, React.ComponentType<SectionComponentProps>>;

  /** Theme configuration */
  config: ThemeConfig;

  /** Optional theme initialization function */
  init?: () => void | Promise<void>;
}
```

### Example

```typescript
import type { ThemeModule } from "@onex/core";
import { HeroDefault, HeroMinimal } from "./sections/hero";
import { FooterDefault } from "./sections/footer";

export const theme: ThemeModule = {
  manifest,
  config,
  sections: {
    "hero-default": HeroDefault,
    "hero-minimal": HeroMinimal,
    "footer-default": FooterDefault,
  },
  init: async () => {
    console.log("Theme initialized");
  },
};

export default theme;
```

---

## Section Component Props

**Location**: `packages/core/src/types/section.ts`
**Tag**: `@public`

Props passed to every section component.

### Interface

```typescript
interface SectionComponentProps {
  /** Section instance data */
  section: SectionInstance;

  /** Section schema */
  schema: SectionSchema;

  /** Selected template definition */
  template: TemplateDefinition;

  /** Whether in edit mode */
  isEditing?: boolean;

  /** Optional data for sections (e.g., products, blog posts) */
  data?: Record<string, unknown>;

  /** Callback when settings change */
  onSettingsChange?: (settings: Settings) => void;

  /** Component management callbacks */
  onComponentAdd?: (componentType: string) => void;
  onComponentUpdate?: (
    componentId: string,
    updates: Partial<ComponentInstance>
  ) => void;
  onComponentRemove?: (componentId: string) => void;
  onComponentReorder?: (componentIds: string[]) => void;
}
```

### Example Section Component

```typescript
import type { SectionComponentProps } from "@onex/core"
import { ButtonComponent, Heading } from "@onex/core/client"

export function HeroMinimal({ section, isEditing }: SectionComponentProps) {
  const { title, subtitle, ctaText, ctaUrl } = section.settings

  return (
    <section className="hero">
      <Heading level={1}>{title}</Heading>
      <p>{subtitle}</p>
      <ButtonComponent href={ctaUrl}>{ctaText}</ButtonComponent>
    </section>
  )
}
```

---

## Theme Configuration

**Location**: `packages/core/src/types/theme.ts`
**Tag**: `@public`

Design tokens for your theme.

### Interface

```typescript
interface ThemeConfig {
  id: string;
  name: string;
  version: string;

  colors: {
    light: ColorPalette;
    dark?: ColorPalette;
  };

  typography: Typography;
  spacing: Spacing;
  borderRadius: BorderRadius;
  breakpoints: Breakpoints;

  tokens?: DesignToken[];
  customCss?: string;
}
```

### Example

```typescript
export const config: ThemeConfig = {
  id: "my-theme",
  name: "My Theme",
  version: "1.0.0",
  colors: {
    light: {
      primary: "#3b82f6",
      secondary: "#8b5cf6",
      background: "#ffffff",
      foreground: "#000000",
      // ... other colors
    },
  },
  typography: {
    fontFamily: {
      heading: "Inter, sans-serif",
      body: "Inter, sans-serif",
      mono: "Fira Code, monospace",
    },
    fontSize: {
      xs: "0.75rem",
      sm: "0.875rem",
      base: "1rem",
      lg: "1.125rem",
      xl: "1.25rem",
      "2xl": "1.5rem",
      "3xl": "1.875rem",
      "4xl": "2.25rem",
      "5xl": "3rem",
    },
    // ... other typography settings
  },
  spacing: {
    xs: "0.25rem",
    sm: "0.5rem",
    md: "1rem",
    lg: "1.5rem",
    xl: "2rem",
    "2xl": "3rem",
    "3xl": "4rem",
    "4xl": "6rem",
  },
  borderRadius: {
    none: "0",
    sm: "0.125rem",
    md: "0.375rem",
    lg: "0.5rem",
    xl: "0.75rem",
    "2xl": "1rem",
    full: "9999px",
  },
  breakpoints: {
    sm: "640px",
    md: "768px",
    lg: "1024px",
    xl: "1280px",
    "2xl": "1536px",
  },
};
```

---

## UI Components

**Location**: `packages/core/src/components/`
**Tag**: `@public`

Pre-built UI components available for use in your sections.

### Available Components

```typescript
import {
  // Layout
  GridContainer,
  FullWidthSection,
  Container,
  Grid,
  Columns,

  // Text
  Heading,
  Paragraph,
  Quote,
  Badge,

  // Interactive
  ButtonComponent,
  Link,
  Divider,
  Spacer,

  // Media
  Image,
  Icon,
  Video,
  Gallery,
  Map,

  // Forms
  Input,
  Textarea,
  Checkbox,
  Select,

  // Advanced
  Card,
  Alert,
  Accordion,
  Tabs,
  Rating,
  Progress,
  Timer,
  Table,
  Code,
} from "@onex/core/client";
```

### Example Usage

```typescript
import { Heading, ButtonComponent, Card } from "@onex/core/client"

export function MySection({ section }: SectionComponentProps) {
  return (
    <Card>
      <Heading level={2}>Section Title</Heading>
      <ButtonComponent href="/learn-more">Learn More</ButtonComponent>
    </Card>
  )
}
```

---

## Utilities

**Location**: `packages/core/src/utils/`
**Tag**: `@public`

Utility functions for common tasks.

### cn() - Class Name Merger

Combines Tailwind classes with proper precedence.

```typescript
import { cn } from "@onex/core/client";

const className = cn(
  "text-base",
  "text-lg", // This wins (last one)
  section.settings.customClass
);
```

### generateId() - UUID Generator

```typescript
import { generateId } from "@onex/core/client";

const id = generateId(); // "abc123-def456-..."
```

---

## Validation

**Location**: `packages/core/src/types/theme.ts`
**Tag**: `@public`

Types for theme validation results.

### Interface

```typescript
interface ValidationResult {
  valid: boolean;
  errors?: ValidationError[];
  warnings?: ValidationWarning[];
}

interface ValidationError {
  code: string;
  message: string;
  path?: string;
}

interface ValidationWarning {
  code: string;
  message: string;
  path?: string;
}
```

### Common Error Codes

- `MISSING_MANIFEST`: manifest.json not found
- `INVALID_MANIFEST`: Manifest schema validation failed
- `BUNDLE_TOO_LARGE`: ZIP exceeds size limit (10MB)
- `UNSAFE_EVAL`: eval() detected
- `UNSAFE_FUNCTION`: Function constructor detected
- `NODE_API`: Node.js API usage detected
- `INCOMPATIBLE_ENGINE`: Engine version mismatch

---

## Security Constraints

**v1.0.0**: Static validation + runtime error boundaries

### Allowed

- ✅ Import from `@onex/core`, `@onex/core/client`
- ✅ Import from `react`, `react-dom`
- ✅ Standard JavaScript/TypeScript
- ✅ Tailwind CSS classes
- ✅ Fetch API for CDN resources only

### Blocked

- ❌ `eval()` or `new Function()`
- ❌ Node.js APIs (`fs`, `path`, `child_process`, etc.)
- ❌ Dynamic imports except from CDN
- ❌ Inline `<script>` tags
- ❌ Bundle size > 1MB

### Runtime Constraints

- ✅ Error boundaries catch render crashes
- ⚠️ No protection against: infinite loops, memory leaks, network abuse
- ⚠️ v2.0.0 will add iframe sandbox for stronger isolation

---

## Engine Version Compatibility

Themes must specify compatible `@onex/core` versions using semver ranges.

### Examples

```typescript
// Exact version
"engine": "1.0.0"

// Compatible with 1.x
"engine": "^1.0.0"

// Compatible with 1.2.0 or higher
"engine": ">=1.2.0"

// Compatible with 1.x but not 2.x
"engine": ">=1.0.0 <2.0.0"
```

### Runtime Enforcement

The platform will check compatibility before loading your theme:

```typescript
if (!semver.satisfies(platformVersion, theme.manifest.engine)) {
  throw new Error("Incompatible theme version");
}
```

---

## Versioning Strategy

Follow semantic versioning for your theme:

- **Major** (2.0.0): Breaking changes to section APIs
- **Minor** (1.1.0): New sections or features
- **Patch** (1.0.1): Bug fixes

### Example Changelog

```
## 1.1.0 (2026-02-01)
- Added: hero-split section variant
- Improved: footer responsive layout

## 1.0.1 (2026-01-25)
- Fixed: button hover state
- Fixed: mobile menu alignment

## 1.0.0 (2026-01-20)
- Initial release
```

---

## Best Practices

### 1. Use TypeScript

```typescript
import type { SectionComponentProps, ThemeManifest } from "@onex/core"

export const manifest: ThemeManifest = { ... }
export function HeroSection(props: SectionComponentProps) { ... }
```

### 2. Export Named and Default

```typescript
export const theme: ThemeModule = { ... }
export { manifest, config }
export default theme
```

### 3. Handle Edit Mode

```typescript
export function MySection({ section, isEditing }: SectionComponentProps) {
  return (
    <div>
      {isEditing && <div className="edit-overlay">Edit Mode</div>}
      {/* Your content */}
    </div>
  )
}
```

### 4. Use Theme Config

```typescript
export function MySection({ section }: SectionComponentProps) {
  const bgColor = section.settings.backgroundColor || config.colors.light.primary

  return <section style={{ backgroundColor: bgColor }}>...</section>
}
```

### 5. Bundle Optimization

```javascript
// esbuild.config.js
module.exports = {
  external: ["@onex/core", "@onex/core/client", "react", "react-dom"],
  minify: true,
  treeShaking: true,
};
```

---

## Migration Guide

### From Internal Themes to Marketplace

If migrating an existing internal theme:

1. **Create manifest.json** with theme metadata
2. **Externalize @onex/core** in build config
3. **Export ThemeModule** structure
4. **Test engine compatibility** with platform
5. **Validate with CLI**: `onex theme validate`
6. **Upload**: `onex theme publish`

---

## Support

- **Documentation**: https://docs.onex.dev/themes
- **API Reference**: This document
- **CLI Help**: `onex theme --help`
- **Issues**: https://github.com/onex/themes/issues

---

_Last Updated: 2026-01-23_
_API Version: 1.0.0_
