# @acorex/components/code-editor

A modular, plugin-based code editor component built on CodeMirror 6.

## Features

- 🔌 **Plugin Architecture** - Fully modular with external plugin support
- 🎨 **Themeable** - Custom theme plugins or platform-aware themes
- 🌍 **Multi-Language** - Support for any language via plugins
- ✨ **Formatting** - Pluggable formatters (Prettier included)
- 📝 **Rich API** - Comprehensive component API with signals
- ♿ **Accessible** - ARIA support and keyboard navigation

## Installation

```bash
npm install @acorex/components
```

## Basic Usage

### With Default Plugins

```typescript
import { Component } from '@angular/core';
import { AXCodeEditorComponent, provideDefaultCodeEditorConfig } from '@acorex/components/code-editor';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  imports: [AXCodeEditorComponent],
  template: `
    <ax-code-editor
      [(value)]="code"
      language="typescript"
      [lineNumbers]="true"
      [formatOnSave]="true"
    />
  `
})
export class AppComponent {
  code = 'const hello = "world";';
}

// Provide default plugins in your app config
bootstrapApplication(AppComponent, {
  providers: [provideDefaultCodeEditorConfig()]
});
```

### Without Default Plugins (Custom Configuration)

```typescript
import {
  provideCodeEditorPlugins,
  JavaScriptLanguagePlugin,
  TypeScriptLanguagePlugin,
  OneDarkThemePlugin,
  LightThemePlugin,
  PrettierFormatterPlugin
} from '@acorex/components/code-editor';

bootstrapApplication(AppComponent, {
  providers: [
    provideCodeEditorPlugins({
      languages: [
        new JavaScriptLanguagePlugin(),
        new TypeScriptLanguagePlugin(),
      ],
      themes: [
        new OneDarkThemePlugin(),
        new LightThemePlugin(),
      ],
      formatters: [
        new PrettierFormatterPlugin(),
      ],
      extensions: []
    })
  ]
});
```

## Plugin System

### Built-in Language Plugins

- `JavaScriptLanguagePlugin` - JavaScript (js, javascript)
- `TypeScriptLanguagePlugin` - TypeScript (ts, typescript)
- `JSONLanguagePlugin` - JSON
- `HTMLLanguagePlugin` - HTML
- `CSSLanguagePlugin` - CSS
- `SassLanguagePlugin` - Sass/SCSS
- `SQLLanguagePlugin` - SQL
- `XMLLanguagePlugin` - XML
- `MarkdownLanguagePlugin` - Markdown

### Built-in Theme Plugins

- `OneDarkThemePlugin` - Dark theme
- `LightThemePlugin` - Light theme

### Built-in Formatter Plugins

- `PrettierFormatterPlugin` - Prettier formatter (JS, TS, JSON, HTML, CSS, Markdown)

### Creating Custom Plugins

#### Custom Language Plugin

```typescript
import { AXCodeEditorLanguagePlugin } from '@acorex/components/code-editor';
import type { Extension } from '@codemirror/state';

export class PythonLanguagePlugin implements AXCodeEditorLanguagePlugin {
  readonly id = 'python';
  readonly name = 'Python';
  readonly version = '1.0.0';
  readonly languages = ['python', 'py'];

  async getExtension(): Promise<Extension> {
    const { python } = await import('@codemirror/lang-python');
    return python();
  }
}
```

#### Custom Theme Plugin

```typescript
import { AXCodeEditorThemePlugin } from '@acorex/components/code-editor';
import type { Extension } from '@codemirror/state';

export class CustomThemePlugin implements AXCodeEditorThemePlugin {
  readonly id = 'custom-theme';
  readonly name = 'Custom Theme';
  readonly version = '1.0.0';
  readonly dark = false;

  async getExtension(): Promise<Extension> {
    const { EditorView } = await import('@codemirror/view');
    return EditorView.theme({
      '&': {
        backgroundColor: '#f5f5f5',
        color: '#333'
      },
      '.cm-gutters': {
        backgroundColor: '#e0e0e0'
      }
    }, { dark: false });
  }
}
```

#### Custom Formatter Plugin

```typescript
import { AXCodeEditorFormatterPlugin } from '@acorex/components/code-editor';

export class CustomFormatterPlugin implements AXCodeEditorFormatterPlugin {
  readonly id = 'custom-formatter';
  readonly name = 'Custom Formatter';
  readonly version = '1.0.0';
  readonly languages = ['custom'];

  async format(text: string, language: string): Promise<string | null> {
    // Your formatting logic
    return text.trim();
  }
}
```

### Runtime Plugin Registration

```typescript
import { inject } from '@angular/core';
import { AXCodeEditorPluginRegistry } from '@acorex/components/code-editor';

export class MyComponent {
  private registry = inject(AXCodeEditorPluginRegistry);

  ngOnInit() {
    // Register plugins at runtime
    this.registry.registerLanguagePlugin(new PythonLanguagePlugin());
    this.registry.registerThemePlugin(new CustomThemePlugin());
    this.registry.registerFormatterPlugin(new CustomFormatterPlugin());
  }
}
```

## Component API

### Inputs

| Input               | Type                               | Default        | Description                      |
| ------------------- | ---------------------------------- | -------------- | -------------------------------- |
| `value`             | `string`                           | `''`           | Editor content (two-way binding) |
| `language`          | `string`                           | `'javascript'` | Language identifier              |
| `theme`             | `string \| null`                   | `null`         | Theme ID (null = platform theme) |
| `readOnly`          | `boolean`                          | `false`        | Read-only mode                   |
| `placeholder`       | `string`                           | `''`           | Placeholder text                 |
| `lineNumbers`       | `boolean`                          | `true`         | Show line numbers                |
| `lineWrapping`      | `boolean`                          | `false`        | Wrap long lines                  |
| `tabSize`           | `number`                           | `2`            | Tab size in spaces               |
| `indentWithTab`     | `boolean`                          | `true`         | Use Tab key for indentation      |
| `height`            | `string \| null`                   | `null`         | Fixed height                     |
| `minHeight`         | `string \| null`                   | `null`         | Minimum height                   |
| `maxHeight`         | `string \| null`                   | `null`         | Maximum height                   |
| `extensions`        | `Extension[]`                      | `[]`           | Additional CodeMirror extensions |
| `customCompletions` | `Completion[] \| CompletionSource` | `null`         | Custom autocomplete              |
| `ariaLabel`         | `string \| null`                   | `null`         | ARIA label                       |
| `focusOnReady`      | `boolean`                          | `false`        | Auto-focus on mount              |
| `formatOnSave`      | `boolean`                          | `false`        | Format on Ctrl+S                 |

### Outputs

| Output        | Type     | Description                      |
| ------------- | -------- | -------------------------------- |
| `valueChange` | `string` | Emits when content changes       |
| `ready`       | `void`   | Emits when editor is initialized |
| `save`        | `string` | Emits on Ctrl+S                  |

### Methods

| Method                 | Returns                   | Description         |
| ---------------------- | ------------------------- | ------------------- |
| `focus()`              | `void`                    | Focus the editor    |
| `selectAll()`          | `void`                    | Select all text     |
| `format(affect?)`      | `Promise<string \| null>` | Format document     |
| `getTotalCharacters()` | `number`                  | Get character count |
| `getTotalLines()`      | `number`                  | Get line count      |

## Examples

### With Custom Theme

```typescript
<ax-code-editor
  [(value)]="code"
  language="typescript"
  theme="one-dark"
/>
```

### With Formatting

```typescript
<ax-code-editor
  [(value)]="code"
  language="json"
  [formatOnSave]="true"
  (save)="onSave($event)"
/>
```

### Programmatic Formatting

```typescript
@Component({
  template: `
    <ax-code-editor #editor [(value)]="code" />
    <button (click)="formatCode()">Format</button>
  `
})
export class MyComponent {
  editor = viewChild<AXCodeEditorComponent>('editor');

  async formatCode() {
    await this.editor().format();
  }
}
```

## Migration from v1

The component now uses a plugin architecture. Update your app configuration:

**Before:**

```typescript
// Languages were hardcoded
```

**After:**

```typescript
import { provideDefaultCodeEditorConfig } from '@acorex/components/code-editor';

bootstrapApplication(AppComponent, {
  providers: [provideDefaultCodeEditorConfig()]
});
```

The `AXCodeEditorSupportedLanguage` type is deprecated but still available for backward compatibility. Use `string` type directly for language inputs.
