# Diff Editor

Side-by-side code comparison editor for visualizing differences between two versions of code. Perfect for code reviews, version comparisons, and merge conflict resolution.

## Capabilities

### DiffEditor Component

Monaco Diff Editor component that displays two code versions side-by-side with highlighted differences.

```typescript { .api }
/**
 * Monaco Diff Editor React component for comparing two code versions
 * @param props - Diff editor configuration and content
 * @returns React component rendering Monaco Diff Editor
 */
declare const DiffEditor: React.ComponentType<DiffEditorProps>;

interface DiffEditorProps {
  /** Original source (left side) value */
  original?: string;
  /** Modified source (right side) value */
  modified?: string;
  /** Language for both models */
  language?: string;
  /** Language for original model only */
  originalLanguage?: string;
  /** Language for modified model only */
  modifiedLanguage?: string;
  /** Path for the original model */
  originalModelPath?: string;
  /** Path for the modified model */
  modifiedModelPath?: string;
  /** Whether to keep original model when unmounting */
  keepCurrentOriginalModel?: boolean;
  /** Whether to keep modified model when unmounting */
  keepCurrentModifiedModel?: boolean;
  /** Theme for the monaco editor */
  theme?: Theme | string;
  /** Loading component shown before editor is mounted */
  loading?: ReactNode;
  /** Diff editor construction options */
  options?: editor.IDiffEditorConstructionOptions;
  /** Width of editor wrapper */
  width?: number | string;
  /** Height of editor wrapper */
  height?: number | string;
  /** CSS class name for editor container */
  className?: string;
  /** Props applied to the wrapper element */
  wrapperProps?: object;
  /** Called before diff editor is mounted */
  beforeMount?: DiffBeforeMount;
  /** Called when diff editor is mounted */
  onMount?: DiffOnMount;
}
```

**Usage Examples:**

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

// Basic diff comparison
function BasicDiffEditor() {
  const originalCode = `function hello() {
  console.log("Hello");
}`;

  const modifiedCode = `function hello(name) {
  console.log("Hello " + name);
}`;

  return (
    <DiffEditor
      height="400px"
      language="javascript"
      original={originalCode}
      modified={modifiedCode}
    />
  );
}

// Advanced diff with custom options
function AdvancedDiffEditor() {
  const original = `const users = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 }
];`;

  const modified = `const users = [
  { name: "Alice", age: 25, active: true },
  { name: "Bob", age: 30, active: false },
  { name: "Charlie", age: 35, active: true }
];`;

  const options = {
    readOnly: false,
    renderSideBySide: true,
    enableSplitViewResizing: true,
    renderOverviewRuler: true,
    ignoreTrimWhitespace: false,
  };

  return (
    <DiffEditor
      height="500px"
      language="javascript"
      original={original}
      modified={modified}
      options={options}
      theme="vs-dark"
    />
  );
}

// Multi-language diff
function MultiLanguageDiff() {
  const tsCode = `interface User {
  name: string;
  age: number;
}`;

  const jsCode = `/**
 * @typedef {Object} User
 * @property {string} name
 * @property {number} age
 */`;

  return (
    <DiffEditor
      height="300px"
      originalLanguage="typescript"
      modifiedLanguage="javascript"
      original={tsCode}
      modified={jsCode}
    />
  );
}
```

### Diff Event Handlers

Event handlers for diff editor lifecycle management.

```typescript { .api }
/**
 * Called when diff editor is mounted
 * @param editor - The standalone diff editor instance
 * @param monaco - The monaco editor namespace
 */
type DiffOnMount = (editor: editor.IStandaloneDiffEditor, monaco: Monaco) => void;

/**
 * Called before diff editor is mounted
 * @param monaco - The monaco editor namespace  
 */
type DiffBeforeMount = (monaco: Monaco) => void;

type MonacoDiffEditor = editor.IStandaloneDiffEditor;
```

**Event Handler Examples:**

```typescript
import { DiffEditor } from "@monaco-editor/react";

function DiffWithHandlers() {
  const handleBeforeMount = (monaco) => {
    // Configure monaco before diff editor creation
    monaco.editor.defineTheme('diffTheme', {
      base: 'vs',
      inherit: true,
      rules: [],
      colors: {
        'diffEditor.insertedTextBackground': '#90EE9050',
        'diffEditor.removedTextBackground': '#FF634750',
      }
    });
  };

  const handleMount = (diffEditor, monaco) => {
    // Access both original and modified editors
    const originalEditor = diffEditor.getOriginalEditor();
    const modifiedEditor = diffEditor.getModifiedEditor();
    
    // Configure diff editor behavior
    diffEditor.updateOptions({
      renderSideBySide: true,
      enableSplitViewResizing: true,
    });
    
    // Focus on modified editor
    modifiedEditor.focus();
    
    // Add navigation commands
    diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.DownArrow, () => {
      diffEditor.goToNextDiff();
    });
    
    diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.UpArrow, () => {
      diffEditor.goToPreviousDiff();
    });
  };

  return (
    <DiffEditor
      height="400px"
      language="javascript"
      original="const a = 1;"
      modified="const a = 2;"
      beforeMount={handleBeforeMount}
      onMount={handleMount}
      theme="diffTheme"
    />
  );
}
```

### Diff Editor Configuration

Configuration options specific to the diff editor functionality.

```typescript { .api }
// Diff editor specific options
interface DiffEditorOptions {
  /** Monaco diff editor construction options */
  options?: editor.IDiffEditorConstructionOptions;
}

// Content configuration for diff comparison
interface DiffContentProps {
  /** Original (left) content */
  original?: string;
  /** Modified (right) content */
  modified?: string;
  /** Language for both sides */
  language?: string;
  /** Separate language for original side */
  originalLanguage?: string;
  /** Separate language for modified side */
  modifiedLanguage?: string;
}

// Model paths for diff editor
interface DiffModelProps {
  /** Path/URI for original model */
  originalModelPath?: string;
  /** Path/URI for modified model */
  modifiedModelPath?: string;
  /** Keep original model when unmounting */
  keepCurrentOriginalModel?: boolean;
  /** Keep modified model when unmounting */
  keepCurrentModifiedModel?: boolean;
}
```

**Configuration Examples:**

```typescript
import { DiffEditor } from "@monaco-editor/react";

// Customized diff editor
function CustomDiffEditor() {
  const diffOptions = {
    // Display options
    renderSideBySide: true,              // Side-by-side vs inline
    renderMarginRevertIcon: true,        // Show revert icons
    renderOverviewRuler: true,           // Show overview ruler
    renderIndicators: true,              // Show change indicators
    
    // Interaction options
    enableSplitViewResizing: true,       // Allow resizing split
    readOnly: false,                     // Allow editing
    originalEditable: false,             // Original side read-only
    
    // Diff algorithm options
    ignoreTrimWhitespace: true,          // Ignore whitespace at line ends
    renderWhitespace: 'selection',       // Show whitespace
    diffWordWrap: 'inherit',             // Word wrapping
    
    // Navigation
    automaticLayout: true,               // Auto-resize
    scrollBeyondLastLine: false,
  };

  return (
    <DiffEditor
      height="600px"
      width="100%"
      language="typescript"
      theme="vs-dark"
      options={diffOptions}
      original="// Original code"
      modified="// Modified code"
    />
  );
}

// File-based diff with model paths
function FileDiffEditor() {
  return (
    <DiffEditor
      height="500px"
      language="javascript"
      originalModelPath="file:///original/main.js"
      modifiedModelPath="file:///modified/main.js"
      original={`function calculate(a, b) {
  return a + b;
}`}
      modified={`function calculate(a, b) {
  // Added validation
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new Error('Arguments must be numbers');
  }
  return a + b;
}`}
      keepCurrentOriginalModel={true}
      keepCurrentModifiedModel={true}
    />
  );
}
```

## Common Use Cases

### Code Review Workflow

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

function CodeReviewDiff() {
  const [currentFile, setCurrentFile] = useState(0);
  
  const changedFiles = [
    {
      filename: "src/utils.js",
      original: `export function formatDate(date) {
  return date.toLocaleDateString();
}`,
      modified: `export function formatDate(date) {
  if (!date || !(date instanceof Date)) {
    throw new Error('Invalid date provided');
  }
  return date.toLocaleDateString();
}`
    },
    {
      filename: "src/api.js", 
      original: `async function fetchUser(id) {
  const response = await fetch(\`/api/users/\${id}\`);
  return response.json();
}`,
      modified: `async function fetchUser(id) {
  const response = await fetch(\`/api/users/\${id}\`);
  if (!response.ok) {
    throw new Error(\`Failed to fetch user: \${response.status}\`);
  }
  return response.json();
}`
    }
  ];

  return (
    <div>
      <div style={{ marginBottom: 10 }}>
        {changedFiles.map((file, index) => (
          <button 
            key={index}
            onClick={() => setCurrentFile(index)}
            style={{
              marginRight: 10,
              fontWeight: currentFile === index ? 'bold' : 'normal',
              background: currentFile === index ? '#007acc' : '#f0f0f0',
              color: currentFile === index ? 'white' : 'black',
              border: 'none',
              padding: '8px 12px',
              cursor: 'pointer'
            }}
          >
            {file.filename}
          </button>
        ))}
      </div>
      
      <DiffEditor
        height="500px"
        language="javascript"
        original={changedFiles[currentFile].original}
        modified={changedFiles[currentFile].modified}
        options={{
          renderSideBySide: true,
          renderMarginRevertIcon: false,
          readOnly: true,
        }}
      />
    </div>
  );
}
```

### Version Comparison

```typescript
function VersionComparisonDiff() {
  const [versions] = useState([
    { version: "1.0.0", code: "const API_URL = 'http://localhost';" },
    { version: "1.1.0", code: "const API_URL = process.env.API_URL || 'http://localhost';" },
    { version: "2.0.0", code: "const API_URL = process.env.REACT_APP_API_URL || 'https://api.example.com';" }
  ]);
  
  const [leftVersion, setLeftVersion] = useState(0);
  const [rightVersion, setRightVersion] = useState(1);

  return (
    <div>
      <div style={{ marginBottom: 10 }}>
        <label>Original: 
          <select value={leftVersion} onChange={(e) => setLeftVersion(+e.target.value)}>
            {versions.map((v, i) => (
              <option key={i} value={i}>{v.version}</option>
            ))}
          </select>
        </label>
        <label style={{ marginLeft: 20 }}>Modified:
          <select value={rightVersion} onChange={(e) => setRightVersion(+e.target.value)}>
            {versions.map((v, i) => (
              <option key={i} value={i}>{v.version}</option>
            ))}
          </select>
        </label>
      </div>
      
      <DiffEditor
        height="300px"
        language="javascript"
        original={versions[leftVersion].code}
        modified={versions[rightVersion].code}
      />
    </div>
  );
}
```