<div markdown="1">
  <sup>Using <a href="https://wangchujiang.com/#/app" target="_blank">my app</a> is also a way to <a href="https://wangchujiang.com/#/sponsor" target="_blank">support</a> me:</sup>
  <br>
  <a target="_blank" href="https://apps.apple.com/app/6758053530" title="Scap: Screenshot & Markup Edit for macOS"><img alt="Scap: Screenshot & Markup Edit" height="52" width="52" src="https://wangchujiang.com/appicon/scap.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6757317079" title="Screen Test for macOS"><img alt="Screen Test" height="52" width="52" src="https://wangchujiang.com/appicon/screen-test.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/Deskmark/6755948110" title="Deskmark for macOS"><img alt="Deskmark" height="52" width="52" src="https://wangchujiang.com/appicon/deskmark.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/Keyzer/6500434773" title="Keyzer for macOS"><img alt="Keyzer" height="52" width="52" src="https://wangchujiang.com/appicon/keyzer.png"></a>
  <a target="_blank" href="https://github.com/jaywcjlove/vidwall-hub" title="Vidwall Hub for macOS"><img alt="Vidwall Hub" height="52" width="52" src="https://wangchujiang.com/appicon/vidwall-hub.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/VidCrop/6752624705" title="VidCrop for macOS"><img alt="VidCrop" height="52" width="52" src="https://wangchujiang.com/appicon/vidcrop.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/Vidwall/6747587746" title="Vidwall for macOS"><img alt="Vidwall" height="52" width="52" src="https://wangchujiang.com/appicon/vidwall.png"></a>
  <a target="_blank" href="https://wangchujiang.com/mousio-hint/" title="Mousio Hint for macOS"><img alt="Mousio Hint" height="52" width="52" src="https://wangchujiang.com/appicon/mousio-hint.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6746747327" title="Mousio for macOS"><img alt="Mousio" height="52" width="52" src="https://wangchujiang.com/appicon/mousio.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6745227444" title="Musicer for macOS"><img alt="Musicer" height="52" width="52" src="https://wangchujiang.com/appicon/musicer.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6743841447" title="Audioer for macOS"><img alt="Audioer" height="52" width="52" src="https://wangchujiang.com/appicon/audioer.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6744690194" title="FileSentinel for macOS"><img alt="FileSentinel" height="52" width="52" src="https://wangchujiang.com/appicon/file-sentinel.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6743495172" title="FocusCursor for macOS"><img alt="FocusCursor" height="52" width="52" src="https://wangchujiang.com/appicon/focus-cursor.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6742680573" title="Videoer for macOS"><img alt="Videoer" height="52" width="52" src="https://wangchujiang.com/appicon/videoer.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6740425504" title="KeyClicker for macOS"><img alt="KeyClicker" height="52" width="52" src="https://wangchujiang.com/appicon/key-clicker.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6739052447" title="DayBar for macOS"><img alt="DayBar" height="52" width="52" src="https://wangchujiang.com/appicon/daybar.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6739444407" title="Iconed for macOS"><img alt="Iconed" height="52" width="52" src="https://wangchujiang.com/appicon/iconed.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6737160756" title="Menuist for macOS"><img alt="Menuist" height="52" width="52" src="https://wangchujiang.com/appicon/rightmenu-master.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6723903021" title="Paste Quick for macOS"><img alt="Quick RSS" height="52" width="52" src="https://wangchujiang.com/appicon/paste-quick.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6670696072" title="Quick RSS for macOS/iOS"><img alt="Quick RSS" height="52" width="52" src="https://wangchujiang.com/appicon/quick-rss.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6670167443" title="Web Serve for macOS"><img alt="Web Serve" height="52" width="52" src="https://wangchujiang.com/appicon/web-serve.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6503953628" title="Copybook Generator for macOS/iOS"><img alt="Copybook Generator" height="52" width="52" src="https://wangchujiang.com/appicon/copybook-generator.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6471227008" title="DevTutor for macOS/iOS"><img alt="DevTutor for SwiftUI" height="52" width="52" src="https://wangchujiang.com/appicon/devtutor.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6479819388" title="RegexMate for macOS/iOS"><img alt="RegexMate" height="52" width="52" src="https://wangchujiang.com/appicon/regex-mate.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6479194014" title="Time Passage for macOS/iOS"><img alt="Time Passage" height="52" width="52" src="https://wangchujiang.com/appicon/time-passage.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6478772538" title="IconizeFolder for macOS"><img alt="Iconize Folder" height="52" width="52" src="https://wangchujiang.com/appicon/iconize-folder.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6478511402" title="Textsound Saver for macOS/iOS"><img alt="Textsound Saver" height="52" width="52" src="https://wangchujiang.com/appicon/textsound-saver.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6476924627" title="Create Custom Symbols for macOS"><img alt="Create Custom Symbols" height="52" width="52" src="https://wangchujiang.com/appicon/create-custom-symbols.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6476452351" title="DevHub for macOS"><img alt="DevHub" height="52" width="52" src="https://wangchujiang.com/appicon/devhub.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6476400184" title="Resume Revise for macOS"><img alt="Resume Revise" height="52" width="52" src="https://wangchujiang.com/appicon/resume-revise.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6472593276" title="Palette Genius for macOS"><img alt="Palette Genius" height="52" width="52" src="https://wangchujiang.com/appicon/palette-genius.png"></a>
  <a target="_blank" href="https://apps.apple.com/app/6470879005" title="Symbol Scribe for macOS"><img alt="Symbol Scribe" height="52" width="52" src="https://wangchujiang.com/appicon/symbol-scribe.png"></a>
  <br><br>
</div>
<hr>

<!--rehype:ignore:start-->

# react-codemirror-merge

<!--rehype:ignore:end-->

[![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor)
[![npm version](https://img.shields.io/npm/v/react-codemirror-merge.svg)](https://www.npmjs.com/package/react-codemirror-merge)

CodeMirror merge view for React.

<a href="https://uiwjs.github.io/react-codemirror/#/merge/document">
  <img width="436" alt="codemirror-theme-androidstudio" src="https://user-images.githubusercontent.com/1680273/230655848-821b9390-9bed-4f28-b52e-f96b59228bfa.png">
</a>

## Install

```bash
npm install react-codemirror-merge --save
```

## Usage

```jsx
import CodeMirrorMerge from 'react-codemirror-merge';
import { EditorView } from 'codemirror';
import { EditorState } from '@codemirror/state';

const Original = CodeMirrorMerge.Original;
const Modified = CodeMirrorMerge.Modified;
let doc = `one
two
three
four
five`;

export const Example = () => {
  return (
    <CodeMirrorMerge orientation="b-a">
      <Original value={doc} />
      <Modified
        value={doc.replace(/t/g, 'T') + 'Six'}
        extensions={[EditorView.editable.of(false), EditorState.readOnly.of(true)]}
      />
    </CodeMirrorMerge>
  );
};
```

## Theme

```jsx
import { useState } from 'react';
import CodeMirrorMerge from 'react-codemirror-merge';
import { EditorView } from 'codemirror';
import { EditorState } from '@codemirror/state';

const Original = CodeMirrorMerge.Original;
const Modified = CodeMirrorMerge.Modified;
let doc = `one
two
three
four
five`;

export const Example = () => {
  const [theme, setTheme] = useState('light');
  return (
    <CodeMirrorMerge orientation="b-a" theme={theme}>
      <Original value={doc} />
      <Modified
        value={doc.replace(/t/g, 'T') + 'Six'}
        extensions={[EditorView.editable.of(false), EditorState.readOnly.of(true)]}
      />
    </CodeMirrorMerge>
  );
};
```

```jsx
import React, { useState } from 'react';
import CodeMirrorMerge from 'react-codemirror-merge';
import { EditorView } from '@codemirror/view';
import { javascript } from '@codemirror/lang-javascript';
import { githubLight, githubDark } from '@uiw/codemirror-theme-github';

const Original = CodeMirrorMerge.Original;
const Modified = CodeMirrorMerge.Modified;
let doc = `function examle() {

}`;

function Example() {
  const [theme, setTheme] = useState('light');
  return (
    <div>
      <CodeMirrorMerge theme={theme === 'light' ? githubLight : githubDark} orientation="a-b">
        <Original extensions={[javascript({ jsx: true }), EditorView.lineWrapping]} value={doc} />
        <Modified extensions={[EditorView.lineWrapping, javascript({ jsx: true })]} value={doc.replace(/e/g, 'T')} />
      </CodeMirrorMerge>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Change Theme {theme}</button>
    </div>
  );
}
```

## Props

```ts
import { Extension } from '@codemirror/state';
export interface CodeMirrorMergeRef extends InternalRef {}
export interface CodeMirrorMergeProps extends React.HTMLAttributes<HTMLDivElement>, MergeConfig {
  theme?: 'light' | 'dark' | 'none' | Extension;
}

interface MergeConfig {
  /**
  Controls whether editor A or editor B is shown first. Defaults
  to `"a-b"`.
  */
  orientation?: 'a-b' | 'b-a';
  /**
  Controls whether revert controls are shown between changed
  chunks.
  */
  revertControls?: 'a-to-b' | 'b-to-a';
  /**
  When given, this function is called to render the button to
  revert a chunk.
  */
  renderRevertControl?: () => HTMLElement;
  /**
  By default, the merge view will mark inserted and deleted text
  in changed chunks. Set this to false to turn that off.
  */
  highlightChanges?: boolean;
  /**
  Controls whether a gutter marker is shown next to changed lines.
  */
  gutter?: boolean;
  /**
  When given, long stretches of unchanged text are collapsed.
  `margin` gives the number of lines to leave visible after/before
  a change (default is 3), and `minSize` gives the minimum amount
  of collapsible lines that need to be present (defaults to 4).
  */
  collapseUnchanged?: {
    margin?: number;
    minSize?: number;
  };
}
```

## Modified Props

```ts
interface ModifiedProps extends Omit<DefaultExtensionsOptions, 'theme'> {
  /**
  The initial document. Defaults to an empty document. Can be
  provided either as a plain string (which will be split into
  lines according to the value of the [`lineSeparator`
  facet](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator)), or an instance of
  the [`Text`](https://codemirror.net/6/docs/ref/#state.Text) class (which is what the state will use
  to represent the document).
  */
  value?: string | Text;
  /**
  The starting selection. Defaults to a cursor at the very start
  of the document.
  */
  selection?:
    | EditorSelection
    | {
        anchor: number;
        head?: number;
      };
  /**
  [Extension(s)](https://codemirror.net/6/docs/ref/#state.Extension) to associate with this state.
  */
  extensions?: Extension;
  /** Fired whenever a change occurs to the document. */
  onChange?(value: string, viewUpdate: ViewUpdate): void;
}

import { Extension } from '@codemirror/state';
import { BasicSetupOptions } from '@uiw/codemirror-extensions-basic-setup';
import { DefaultExtensionsOptions } from '@uiw/react-codemirror';

export interface DefaultExtensionsOptions {
  indentWithTab?: boolean;
  basicSetup?: boolean | BasicSetupOptions;
  placeholder?: string | HTMLElement;
  theme?: 'light' | 'dark' | 'none' | Extension;
  readOnly?: boolean;
  editable?: boolean;
}
```

## Original Props

```ts
interface OriginalProps extends Omit<DefaultExtensionsOptions, 'theme'> {
  /**
  The initial document. Defaults to an empty document. Can be
  provided either as a plain string (which will be split into
  lines according to the value of the [`lineSeparator`
  facet](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator)), or an instance of
  the [`Text`](https://codemirror.net/6/docs/ref/#state.Text) class (which is what the state will use
  to represent the document).
  */
  value?: string | Text;
  /**
  The starting selection. Defaults to a cursor at the very start
  of the document.
  */
  selection?:
    | EditorSelection
    | {
        anchor: number;
        head?: number;
      };
  /**
  [Extension(s)](https://codemirror.net/6/docs/ref/#state.Extension) to associate with this state.
  */
  extensions?: Extension;
  /** Fired whenever a change occurs to the document. */
  onChange?(value: string, viewUpdate: ViewUpdate): void;
}

import { Extension } from '@codemirror/state';
import { BasicSetupOptions } from '@uiw/codemirror-extensions-basic-setup';
import { DefaultExtensionsOptions } from '@uiw/react-codemirror';

export interface DefaultExtensionsOptions {
  indentWithTab?: boolean;
  basicSetup?: boolean | BasicSetupOptions;
  placeholder?: string | HTMLElement;
  theme?: 'light' | 'dark' | 'none' | Extension;
  readOnly?: boolean;
  editable?: boolean;
}
```

## Contributors

As always, thanks to our amazing contributors!

<a href="https://github.com/uiwjs/react-codemirror/graphs/contributors">
  <img src="https://uiwjs.github.io/react-codemirror/CONTRIBUTORS.svg" />
</a>

Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).

## License

Licensed under the MIT License.
