npm package: @orsetra/openapi-editor
Description: Professional OpenAPI 3.0/3.1 Editor - React component for editing and validating OpenAPI specifications
Author: orsetra Team
Latest version: 0.2.19

# @orsetra/openapi-editor

Professional OpenAPI 3.0/3.1 Editor - React component for editing and validating OpenAPI specifications.

[![npm version](https://badge.fury.io/js/%40orsetra%2Fopenapi-editor.svg)](https://www.npmjs.com/package/@orsetra/openapi-editor)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- ✅ **Full OpenAPI 3.0/3.1 Support** - Complete specification editing
- 🎨 **Monaco Editor** - Powered by VS Code's editor with syntax highlighting
- 🔍 **Real-time Validation** - Instant feedback on specification errors
- 📁 **Multi-file Projects** - Support for split specifications with $ref
- 🔄 **Sync Integration** - Built-in support for external sync providers
- 📦 **Import/Export** - ZIP file support for project portability
- 🎯 **TypeScript** - Full type definitions included
- 🌐 **Swagger UI Preview** - Live preview of your API documentation
- 💾 **Local Storage** - Automatic persistence of your work

## Installation

```bash
npm install @orsetra/openapi-editor
```

## Quick Start

```tsx
import { OpenapiEditor, useOpenapiEditor } from '@orsetra/openapi-editor';
import '@orsetra/openapi-editor/dist/style.css';

function App() {
  const { editorRef, exportToZip } = useOpenapiEditor();

  const handleExport = async () => {
    const blob = await exportToZip();
    // Save the blob...
  };

  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <OpenapiEditor 
        ref={editorRef}
        menubar={true}
        readonly={false}
      />
      <button onClick={handleExport}>Export Project</button>
    </div>
  );
}
```

## API Reference

### OpenapiEditor Component

#### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `menubar` | `boolean` | `true` | Show/hide the top menubar |
| `readonly` | `boolean` | `false` | Make the editor read-only |
| `projectId` | `string` | - | Project ID for synchronization |
| `className` | `string` | - | Custom CSS class name |
| `style` | `React.CSSProperties` | - | Custom inline styles |
| `syncConfig` | `SyncConfig` | - | Sync configuration object |
| `autoLoad` | `boolean` | `false` | Auto-load project on mount |
| `onSyncConfigured` | `function` | - | Callback when sync is configured |
| `onReady` | `function` | - | Callback when editor is ready |

#### Ref Methods

```tsx
const editorRef = useRef<OpenapiEditorRef>(null);

// Load from ZIP
await editorRef.current.loadFromZip(zipBlob);

// Export to ZIP
const blob = await editorRef.current.exportToZip();

// Validate project
const validation = await editorRef.current.isProjectValid();

// Get project info
const info = await editorRef.current.getProjectInfo();

// Get all endpoints
const endpoints = await editorRef.current.getEndpoints();

// Import files
await editorRef.current.importFiles(files, { conflictStrategy: 'overwrite' });
```

### useOpenapiEditor Hook

Convenient hook for managing the editor:

```tsx
const {
  editorRef,
  isReady,
  loadFromZip,
  exportToZip,
  isProjectValid,
  getProjectInfo,
  getEndpoints,
  importFiles,
  openImportModal,
  configureSync,
  startSync,
  stopSync,
  syncNow,
  getSyncStatus,
  resetSync,
  loadProjectFromSync,
} = useOpenapiEditor(options);
```

## Examples

### Basic Editor

```tsx
import { OpenapiEditor } from '@orsetra/openapi-editor';
import '@orsetra/openapi-editor/dist/style.css';

function BasicEditor() {
  return (
    <OpenapiEditor 
      menubar={true}
      readonly={false}
    />
  );
}
```

### With Validation

```tsx
import { OpenapiEditor, useOpenapiEditor } from '@orsetra/openapi-editor';

function ValidatedEditor() {
  const { editorRef, isProjectValid } = useOpenapiEditor();

  const handleValidate = async () => {
    const result = await isProjectValid();
    
    if (result.valid) {
      alert('✅ Specification is valid!');
    } else {
      console.error('Validation errors:', result.errors);
      alert(`❌ Found ${result.errorCount} error(s)`);
    }
  };

  return (
    <>
      <OpenapiEditor ref={editorRef} />
      <button onClick={handleValidate}>Validate</button>
    </>
  );
}
```

### With Sync Provider

```tsx
import { OpenapiEditor, useOpenapiEditor, SyncProvider } from '@orsetra/openapi-editor';

const syncProvider: SyncProvider = {
  loadProject: async (projectId) => {
    const response = await fetch(`/api/projects/${projectId}`);
    const data = await response.json();
    
    return {
      projectId,
      projectType: 'oas3:api',
      files: data.files,
    };
  },

  syncChanges: async (projectId, changes) => {
    const response = await fetch(`/api/projects/${projectId}/sync`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ changes }),
    });

    return response.json();
  },

  isReady: async () => {
    const response = await fetch('/api/health');
    return response.ok;
  },
};

function SyncedEditor() {
  const { editorRef } = useOpenapiEditor();

  return (
    <OpenapiEditor 
      ref={editorRef}
      syncConfig={{
        provider: syncProvider,
        projectId: 'my-project-123',
        interval: 30000, // Sync every 30 seconds
        autoSync: true,
      }}
      autoLoad={true}
      onSyncConfigured={(event) => {
        console.log('Sync configured:', event);
      }}
    />
  );
}
```

### Import/Export

```tsx
import { useOpenapiEditor } from '@orsetra/openapi-editor';

function ImportExportExample() {
  const { editorRef, loadFromZip, exportToZip } = useOpenapiEditor();

  const handleImport = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;

    const info = await loadFromZip(file);
    console.log(`Loaded: ${info.name} v${info.version}`);
  };

  const handleExport = async () => {
    const blob = await exportToZip();
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'openapi-project.zip';
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <>
      <OpenapiEditor ref={editorRef} />
      <input type="file" accept=".zip" onChange={handleImport} />
      <button onClick={handleExport}>Export</button>
    </>
  );
}
```

### Read-only Viewer

```tsx
import { OpenapiEditor, useOpenapiEditor } from '@orsetra/openapi-editor';

function ApiViewer() {
  const { editorRef, getEndpoints } = useOpenapiEditor();

  const showEndpoints = async () => {
    const endpoints = await getEndpoints();
    console.log('API Endpoints:', endpoints);
  };

  return (
    <>
      <OpenapiEditor 
        ref={editorRef}
        readonly={true}
        menubar={false}
      />
      <button onClick={showEndpoints}>Show Endpoints</button>
    </>
  );
}
```

## TypeScript Support

Full TypeScript definitions are included:

```tsx
import type {
  OpenapiEditorProps,
  OpenapiEditorRef,
  SyncConfig,
  SyncProvider,
  FileChange,
  SyncResult,
  ProjectData,
  UseOpenapiEditorOptions,
  UseOpenapiEditorReturn,
} from '@orsetra/openapi-editor';
```

## Sync Provider Interface

Implement custom sync providers:

```typescript
interface SyncProvider {
  loadProject(projectId: string): Promise<ProjectData>;
  syncChanges(projectId: string, changes: FileChange[]): Promise<SyncResult>;
  isReady?(): Promise<boolean>;
}

interface ProjectData {
  projectId: string;
  projectType?: string;
  description?: string;
  files: Array<{
    path: string;
    content: string;
    format: 'json' | 'yaml';
  }>;
}

interface FileChange {
  path: string;
  type: 'created' | 'modified' | 'deleted';
  content: string | null;
  format: 'json' | 'yaml';
  timestamp: number;
}

interface SyncResult {
  success: boolean;
  syncedCount: number;
  error?: string;
  timestamp: number;
}
```

## Styling

Import the default styles:

```tsx
import '@orsetra/openapi-editor/dist/style.css';
```

Or customize with your own CSS by targeting the component classes.

## Browser Support

- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)

## Requirements

- React >= 18.0.0
- react-dom >= 18.0.0

## License

MIT © orsetra Team

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Support

For issues and questions, please use the [GitHub Issues](https://github.com/orsetra/openapi-editor/issues) page.

## Related Projects

- [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification)
- [Swagger UI](https://github.com/swagger-api/swagger-ui)
- [Monaco Editor](https://github.com/microsoft/monaco-editor)