Skip to content

Commit

Permalink
feat: add react-codemirror-merge component (#455).
Browse files Browse the repository at this point in the history
  • Loading branch information
jaywcjlove committed Apr 7, 2023
1 parent 83f1d1f commit ba3d076
Show file tree
Hide file tree
Showing 21 changed files with 515 additions and 53 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -92,6 +92,12 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: 📦 react-codemirror-merge publish to NPM
run: npm publish --access public
working-directory: ./merge/
continue-on-error: true
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: 📦 @uiw/codemirror-themes publish to NPM
run: npm publish --access public
Expand Down Expand Up @@ -364,6 +370,20 @@ jobs:
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

- name: "Modify react-codemirror-merge => @uiwjs/react-codemirror-merge"
uses: jaywcjlove/github-action-package@main
continue-on-error: true
with:
path: merge/package.json
rename: "@uiwjs/react-codemirror-merge"

- run: npm publish
name: 📦 @uiwjs/react-codemirror-merge publish to NPM
working-directory: merge
continue-on-error: true
env:
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

- name: Modify @uiw/codemirror-themes => @uiwjs/codemirror-themes
uses: jaywcjlove/github-action-package@main
with:
Expand Down
30 changes: 29 additions & 1 deletion core/README.md
Expand Up @@ -183,6 +183,34 @@ export default function App() {
}
```

## Codemirror Merge

```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>
<Original value={doc} />
<Modified
value={doc.replace(/t/g, 'T') + 'Six'}
extensions={[EditorView.editable.of(false), EditorState.readOnly.of(true)]}
/>
</CodeMirrorMerge>
);
};
```

## Support Hook

[![Open in CodeSandbox](https://img.shields.io/badge/Open%20in-CodeSandbox-blue?logo=codesandbox)](https://codesandbox.io/embed/react-codemirror-example-codemirror-6-hook-yr4vg?fontsize=14&hidenavigation=1&theme=dark)
Expand Down Expand Up @@ -397,7 +425,7 @@ export interface ReactCodeMirrorProps
*/
readOnly?: boolean;
/**
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
* or behaves according to the browser's default behavior (`false`).
* @default true
*/
Expand Down
71 changes: 71 additions & 0 deletions core/src/getDefaultExtensions.ts
@@ -0,0 +1,71 @@
import { Extension } from '@codemirror/state';
import { indentWithTab } from '@codemirror/commands';
import { basicSetup, BasicSetupOptions } from '@uiw/codemirror-extensions-basic-setup';
import { EditorView, keymap, placeholder } from '@codemirror/view';
import { oneDark } from '@codemirror/theme-one-dark';
import { EditorState } from '@codemirror/state';

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

export const getDefaultExtensions = (optios: DefaultExtensionsOptions = {}): Extension[] => {
const {
indentWithTab: defaultIndentWithTab = true,
editable = true,
readOnly = false,
theme = 'light',
placeholder: placeholderStr = '',
basicSetup: defaultBasicSetup = true,
} = optios;
const getExtensions: Extension[] = [];
const defaultLightThemeOption = EditorView.theme(
{
'&': {
backgroundColor: '#fff',
},
},
{
dark: false,
},
);
if (defaultIndentWithTab) {
getExtensions.unshift(keymap.of([indentWithTab]));
}
if (defaultBasicSetup) {
if (typeof defaultBasicSetup === 'boolean') {
getExtensions.unshift(basicSetup());
} else {
getExtensions.unshift(basicSetup(defaultBasicSetup));
}
}
if (placeholderStr) {
getExtensions.unshift(placeholder(placeholderStr));
}
switch (theme) {
case 'light':
getExtensions.push(defaultLightThemeOption);
break;
case 'dark':
getExtensions.push(oneDark);
break;
case 'none':
break;
default:
getExtensions.push(theme);
break;
}
if (editable === false) {
getExtensions.push(EditorView.editable.of(false));
}
if (readOnly) {
getExtensions.push(EditorState.readOnly.of(true));
}

return [...getExtensions];
};
3 changes: 2 additions & 1 deletion core/src/index.tsx
Expand Up @@ -7,6 +7,7 @@ import { Statistics } from './utils';

export * from '@uiw/codemirror-extensions-basic-setup';
export * from './useCodeMirror';
export * from './getDefaultExtensions';
export * from './utils';

export interface ReactCodeMirrorProps
Expand Down Expand Up @@ -45,7 +46,7 @@ export interface ReactCodeMirrorProps
*/
readOnly?: boolean;
/**
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
* or behaves according to the browser's default behavior (`false`).
* @default true
*/
Expand Down
60 changes: 11 additions & 49 deletions core/src/useCodeMirror.ts
@@ -1,9 +1,7 @@
import { useEffect, useState } from 'react';
import { Annotation, EditorState, StateEffect } from '@codemirror/state';
import { indentWithTab } from '@codemirror/commands';
import { EditorView, keymap, ViewUpdate, placeholder } from '@codemirror/view';
import { basicSetup } from '@uiw/codemirror-extensions-basic-setup';
import { oneDark } from '@codemirror/theme-one-dark';
import { EditorView, ViewUpdate } from '@codemirror/view';
import { getDefaultExtensions } from './getDefaultExtensions';
import { getStatistics } from './utils';
import { ReactCodeMirrorProps } from '.';

Expand Down Expand Up @@ -41,16 +39,6 @@ export function useCodeMirror(props: UseCodeMirror) {
const [container, setContainer] = useState<HTMLDivElement>();
const [view, setView] = useState<EditorView>();
const [state, setState] = useState<EditorState>();
const defaultLightThemeOption = EditorView.theme(
{
'&': {
backgroundColor: '#fff',
},
},
{
dark: false,
},
);
const defaultThemeOption = EditorView.theme({
'&': {
height,
Expand All @@ -76,42 +64,16 @@ export function useCodeMirror(props: UseCodeMirror) {
onStatistics && onStatistics(getStatistics(vu));
});

let getExtensions = [updateListener, defaultThemeOption];
if (defaultIndentWithTab) {
getExtensions.unshift(keymap.of([indentWithTab]));
}
if (defaultBasicSetup) {
if (typeof defaultBasicSetup === 'boolean') {
getExtensions.unshift(basicSetup());
} else {
getExtensions.unshift(basicSetup(defaultBasicSetup));
}
}

if (placeholderStr) {
getExtensions.unshift(placeholder(placeholderStr));
}

switch (theme) {
case 'light':
getExtensions.push(defaultLightThemeOption);
break;
case 'dark':
getExtensions.push(oneDark);
break;
case 'none':
break;
default:
getExtensions.push(theme);
break;
}
const defaultExtensions = getDefaultExtensions({
theme,
editable: true,
readOnly: false,
placeholder: placeholderStr,
indentWithTab: defaultIndentWithTab,
basicSetup: defaultBasicSetup,
});

if (editable === false) {
getExtensions.push(EditorView.editable.of(false));
}
if (readOnly) {
getExtensions.push(EditorState.readOnly.of(true));
}
let getExtensions = [updateListener, defaultThemeOption, ...defaultExtensions];

if (onUpdate && typeof onUpdate === 'function') {
getExtensions.push(EditorView.updateListener.of(onUpdate));
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
@@ -1,5 +1,5 @@
{
"version": "4.19.11",
"packages": ["themes/**", "core", "www"],
"packages": ["themes/**", "core", "merge", "www"],
"useWorkspaces": true
}
57 changes: 57 additions & 0 deletions merge/README.md
@@ -0,0 +1,57 @@
<!--rehype:ignore:start-->

# react-codemirror-merge

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

[![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.

## 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>
<Original value={doc} />
<Modified
value={doc.replace(/t/g, 'T') + 'Six'}
extensions={[EditorView.editable.of(false), EditorState.readOnly.of(true)]}
/>
</CodeMirrorMerge>
);
};
```

## 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.
56 changes: 56 additions & 0 deletions merge/package.json
@@ -0,0 +1,56 @@
{
"name": "react-codemirror-merge",
"version": "0.0.1",
"description": "CodeMirror merge view for React.",
"homepage": "https://uiwjs.github.io/react-codemirror",
"author": "kenny wong <wowohoo@qq.com>",
"license": "MIT",
"main": "./cjs/index.js",
"module": "./esm/index.js",
"scripts": {
"watch": "tsbb watch src/*.tsx --use-babel",
"build": "tsbb build src/*.tsx --use-babel",
"test": "tsbb test --env=jsdom",
"coverage": "tsbb test --env=jsdom --coverage --bail"
},
"repository": {
"type": "git",
"url": "https://github.com/uiwjs/react-codemirror.git"
},
"files": [
"dist",
"src",
"esm",
"cjs"
],
"peerDependencies": {
"@babel/runtime": ">=7.11.0",
"@codemirror/state": ">=6.0.0",
"@codemirror/theme-one-dark": ">=6.0.0",
"@codemirror/view": ">=6.0.0",
"codemirror": ">=6.0.0",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
},
"dependencies": {
"@babel/runtime": "^7.18.6",
"@uiw/react-codemirror": "^4.19.11",
"@codemirror/merge": "^6.0.1"
},
"keywords": [
"react",
"codemirror",
"codemirror6",
"react-codemirror",
"editor",
"syntax",
"ide",
"code"
],
"jest": {
"coverageReporters": [
"lcov",
"json-summary"
]
}
}

0 comments on commit ba3d076

Please sign in to comment.