# Monaco Hook

React hook for accessing the Monaco Editor instance and its APIs across components without needing to pass instances through props.

## Capabilities

### useMonaco Hook

React hook that provides access to the Monaco Editor instance once it's loaded.

```typescript { .api }
/**
 * React hook for accessing the Monaco Editor instance
 * @returns Monaco instance or null if not yet loaded
 */
function useMonaco(): Monaco | null;

type Monaco = typeof monaco;
```

**Usage Examples:**

```typescript
import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

// Basic Monaco instance access
function MonacoStatus() {
  const monaco = useMonaco();

  useEffect(() => {
    if (monaco) {
      console.log("Monaco Editor is ready!");
      console.log("Available languages:", monaco.languages.getLanguages());
    }
  }, [monaco]);

  return (
    <div>
      Monaco Status: {monaco ? "Loaded" : "Loading..."}
    </div>
  );
}

// Custom language configuration
function CustomLanguageSetup() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Register custom language
    monaco.languages.register({ id: 'myLang' });

    // Define language syntax
    monaco.languages.setMonarchTokensProvider('myLang', {
      tokenizer: {
        root: [
          [/\[error.*/, "custom-error"],
          [/\[notice.*/, "custom-notice"],
          [/\[info.*/, "custom-info"],
          [/\[[a-zA-Z 0-9:]+\]/, "custom-date"],
        ]
      }
    });

    // Configure language features
    monaco.languages.setLanguageConfiguration('myLang', {
      brackets: [
        ['[', ']'],
        ['(', ')'],
        ['{', '}']
      ],
      autoClosingPairs: [
        { open: '[', close: ']' },
        { open: '(', close: ')' },
        { open: '{', close: '}' },
      ]
    });

  }, [monaco]);

  return <div>Custom language configured</div>;
}
```

### Theme Management

Use the Monaco instance to define and manage custom themes across your application.

```typescript { .api }
// Theme definition interface (from Monaco Editor)
interface ThemeDefinition {
  base: 'vs' | 'vs-dark' | 'hc-black';
  inherit: boolean;
  rules: TokenThemeRule[];
  colors: { [colorId: string]: string };
}

interface TokenThemeRule {
  token: string;
  foreground?: string;
  background?: string;
  fontStyle?: string;
}
```

**Theme Examples:**

```typescript
import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

function ThemeManager() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Define custom dark theme
    monaco.editor.defineTheme('customDark', {
      base: 'vs-dark',
      inherit: true,
      rules: [
        { token: 'comment', foreground: '6A9955', fontStyle: 'italic' },
        { token: 'keyword', foreground: '569CD6', fontStyle: 'bold' },
        { token: 'string', foreground: 'CE9178' },
        { token: 'number', foreground: 'B5CEA8' },
      ],
      colors: {
        'editor.background': '#1e1e1e',
        'editor.foreground': '#d4d4d4',
        'editorLineNumber.foreground': '#858585',
        'editorCursor.foreground': '#ffffff',
        'editor.selectionBackground': '#264f78',
        'editor.lineHighlightBackground': '#2d2d30',
      }
    });

    // Define custom light theme
    monaco.editor.defineTheme('customLight', {
      base: 'vs',
      inherit: true,
      rules: [
        { token: 'comment', foreground: '008000', fontStyle: 'italic' },
        { token: 'keyword', foreground: '0000ff', fontStyle: 'bold' },
        { token: 'string', foreground: 'a31515' },
        { token: 'number', foreground: '098658' },
      ],
      colors: {
        'editor.background': '#ffffff',
        'editor.foreground': '#000000',
        'editorLineNumber.foreground': '#237893',
        'editor.selectionBackground': '#add6ff',
        'editor.lineHighlightBackground': '#f0f0f0',
      }
    });

  }, [monaco]);

  const applyTheme = (themeName) => {
    if (monaco) {
      monaco.editor.setTheme(themeName);
    }
  };

  return (
    <div>
      <button onClick={() => applyTheme('customDark')}>Dark Theme</button>
      <button onClick={() => applyTheme('customLight')}>Light Theme</button>
      <button onClick={() => applyTheme('vs-dark')}>VS Dark</button>
      <button onClick={() => applyTheme('vs')}>VS Light</button>
    </div>
  );
}
```

### Language Service Configuration

Configure TypeScript/JavaScript language services and other language features.

```typescript { .api }
// Language service configuration interfaces (from Monaco Editor)
interface LanguageServiceDefaults {
  setCompilerOptions(options: CompilerOptions): void;
  setDiagnosticsOptions(options: DiagnosticsOptions): void;
  addExtraLib(content: string, filePath?: string): void;
  setEagerModelSync(value: boolean): void;
}
```

**Language Service Examples:**

```typescript
import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

function TypeScriptConfiguration() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Configure TypeScript compiler options
    monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
      target: monaco.languages.typescript.ScriptTarget.ES2020,
      allowNonTsExtensions: true,
      moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
      module: monaco.languages.typescript.ModuleKind.CommonJS,
      noEmit: true,
      esModuleInterop: true,
      jsx: monaco.languages.typescript.JsxEmit.React,
      reactNamespace: "React",
      allowJs: true,
      typeRoots: ["node_modules/@types"]
    });

    // Configure diagnostics
    monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
      noSemanticValidation: false,
      noSyntaxValidation: false,
      noSuggestionDiagnostics: false
    });

    // Add type definitions
    const reactTypes = `
      declare module "react" {
        export interface FC<P = {}> {
          (props: P & { children?: ReactNode }): ReactElement | null;
        }
        export type ReactNode = ReactElement | string | number | boolean | null | undefined;
        export interface ReactElement<P = any> {
          type: string | FC<P>;
          props: P;
          key: string | number | null;
        }
      }
    `;

    monaco.languages.typescript.typescriptDefaults.addExtraLib(
      reactTypes,
      'file:///node_modules/@types/react/index.d.ts'
    );

    // Enable eager model sync for better performance
    monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true);

  }, [monaco]);

  return <div>TypeScript language service configured</div>;
}

function CustomCompletionProvider() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Register custom completion provider
    const disposable = monaco.languages.registerCompletionItemProvider('javascript', {
      provideCompletionItems: (model, position) => {
        const suggestions = [
          {
            label: 'console.log',
            kind: monaco.languages.CompletionItemKind.Function,
            documentation: 'Log a message to the console',
            insertText: 'console.log($1);',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            range: {
              startLineNumber: position.lineNumber,
              endLineNumber: position.lineNumber,
              startColumn: position.column,
              endColumn: position.column
            }
          },
          {
            label: 'async function',
            kind: monaco.languages.CompletionItemKind.Snippet,
            documentation: 'Create an async function',
            insertText: 'async function ${1:functionName}(${2:params}) {\n\t$0\n}',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            range: {
              startLineNumber: position.lineNumber,
              endLineNumber: position.lineNumber,
              startColumn: position.column,
              endColumn: position.column
            }
          }
        ];

        return { suggestions };
      }
    });

    // Cleanup on unmount
    return () => disposable.dispose();
  }, [monaco]);

  return <div>Custom completion provider registered</div>;
}
```

### Global Monaco Configuration

Configure Monaco Editor settings that apply to all editor instances.

```typescript { .api }
// Global configuration options
interface GlobalMonacoConfig {
  /** Configure default options for all editors */
  setGlobalOptions(options: editor.IEditorOptions): void;
  /** Register global commands */
  addGlobalCommand(keybinding: number, handler: () => void): void;
  /** Configure language features globally */
  configureLanguageGlobally(languageId: string, config: any): void;
}
```

**Global Configuration Examples:**

```typescript
import React, { useEffect } from "react";
import { useMonaco } from "@monaco-editor/react";

function GlobalMonacoSetup() {
  const monaco = useMonaco();

  useEffect(() => {
    if (!monaco) return;

    // Set global editor defaults
    monaco.editor.EditorOptions.fontSize.defaultValue = 14;
    monaco.editor.EditorOptions.fontFamily.defaultValue = 'Monaco, Menlo, monospace';
    monaco.editor.EditorOptions.lineHeight.defaultValue = 1.6;

    // Configure global key bindings
    const formatAction = {
      id: 'format-document',
      label: 'Format Document', 
      keybindings: [monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.KeyF],
      run: (editor) => {
        editor.getAction('editor.action.formatDocument').run();
      }
    };

    // Register global actions
    monaco.editor.addEditorAction(formatAction);

    // Configure language defaults
    const jsDefaults = monaco.languages.typescript.javascriptDefaults;
    jsDefaults.setCompilerOptions({
      allowNonTsExtensions: true,
      allowJs: true
    });

  }, [monaco]);

  return <div>Global Monaco configuration applied</div>;
}
```

## Integration Patterns

### Provider Pattern

Create a Monaco context provider for app-wide access.

```typescript
import React, { createContext, useContext, useEffect, useState } from "react";
import { useMonaco } from "@monaco-editor/react";

const MonacoContext = createContext(null);

export function MonacoProvider({ children }) {
  const monaco = useMonaco();
  const [isConfigured, setIsConfigured] = useState(false);

  useEffect(() => {
    if (!monaco || isConfigured) return;

    // Apply global configuration
    monaco.editor.defineTheme('appTheme', {
      base: 'vs-dark',
      inherit: true,
      rules: [],
      colors: {
        'editor.background': '#1a1a1a',
      }
    });

    setIsConfigured(true);
  }, [monaco, isConfigured]);

  return (
    <MonacoContext.Provider value={{ monaco, isConfigured }}>
      {children}
    </MonacoContext.Provider>
  );
}

export function useAppMonaco() {
  const context = useContext(MonacoContext);
  if (!context) {
    throw new Error('useAppMonaco must be used within MonacoProvider');
  }
  return context;
}
```

### Conditional Rendering

Only render Monaco-dependent components after Monaco is loaded.

```typescript
import React from "react";
import { useMonaco } from "@monaco-editor/react";
import Editor from "@monaco-editor/react";

function ConditionalEditor() {
  const monaco = useMonaco();

  if (!monaco) {
    return <div>Loading Monaco Editor...</div>;
  }

  return (
    <div>
      <Editor
        height="400px"
        language="javascript"
        defaultValue="// Monaco is ready!"
      />
    </div>
  );
}
```