Skip to content

Commit ba3d076

Browse files
committed
feat: add react-codemirror-merge component (#455).
1 parent 83f1d1f commit ba3d076

21 files changed

+515
-53
lines changed

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ jobs:
9292
env:
9393
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
9494

95+
- name: 📦 react-codemirror-merge publish to NPM
96+
run: npm publish --access public
97+
working-directory: ./merge/
98+
continue-on-error: true
99+
env:
100+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
95101

96102
- name: 📦 @uiw/codemirror-themes publish to NPM
97103
run: npm publish --access public
@@ -364,6 +370,20 @@ jobs:
364370
env:
365371
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
366372

373+
- name: "Modify react-codemirror-merge => @uiwjs/react-codemirror-merge"
374+
uses: jaywcjlove/github-action-package@main
375+
continue-on-error: true
376+
with:
377+
path: merge/package.json
378+
rename: "@uiwjs/react-codemirror-merge"
379+
380+
- run: npm publish
381+
name: 📦 @uiwjs/react-codemirror-merge publish to NPM
382+
working-directory: merge
383+
continue-on-error: true
384+
env:
385+
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
386+
367387
- name: Modify @uiw/codemirror-themes => @uiwjs/codemirror-themes
368388
uses: jaywcjlove/github-action-package@main
369389
with:

core/README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,34 @@ export default function App() {
183183
}
184184
```
185185

186+
## Codemirror Merge
187+
188+
```jsx
189+
import CodeMirrorMerge from 'react-codemirror-merge';
190+
import { EditorView } from 'codemirror';
191+
import { EditorState } from '@codemirror/state';
192+
193+
const Original = CodeMirrorMerge.Original;
194+
const Modified = CodeMirrorMerge.Modified;
195+
let doc = `one
196+
two
197+
three
198+
four
199+
five`;
200+
201+
export const Example = () => {
202+
return (
203+
<CodeMirrorMerge>
204+
<Original value={doc} />
205+
<Modified
206+
value={doc.replace(/t/g, 'T') + 'Six'}
207+
extensions={[EditorView.editable.of(false), EditorState.readOnly.of(true)]}
208+
/>
209+
</CodeMirrorMerge>
210+
);
211+
};
212+
```
213+
186214
## Support Hook
187215

188216
[![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)
@@ -397,7 +425,7 @@ export interface ReactCodeMirrorProps
397425
*/
398426
readOnly?: boolean;
399427
/**
400-
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
428+
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
401429
* or behaves according to the browser's default behavior (`false`).
402430
* @default true
403431
*/

core/src/getDefaultExtensions.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Extension } from '@codemirror/state';
2+
import { indentWithTab } from '@codemirror/commands';
3+
import { basicSetup, BasicSetupOptions } from '@uiw/codemirror-extensions-basic-setup';
4+
import { EditorView, keymap, placeholder } from '@codemirror/view';
5+
import { oneDark } from '@codemirror/theme-one-dark';
6+
import { EditorState } from '@codemirror/state';
7+
8+
export type DefaultExtensionsOptions = {
9+
indentWithTab?: boolean;
10+
basicSetup?: boolean | BasicSetupOptions;
11+
placeholder?: string | HTMLElement;
12+
theme?: 'light' | 'dark' | 'none' | Extension;
13+
readOnly?: boolean;
14+
editable?: boolean;
15+
};
16+
17+
export const getDefaultExtensions = (optios: DefaultExtensionsOptions = {}): Extension[] => {
18+
const {
19+
indentWithTab: defaultIndentWithTab = true,
20+
editable = true,
21+
readOnly = false,
22+
theme = 'light',
23+
placeholder: placeholderStr = '',
24+
basicSetup: defaultBasicSetup = true,
25+
} = optios;
26+
const getExtensions: Extension[] = [];
27+
const defaultLightThemeOption = EditorView.theme(
28+
{
29+
'&': {
30+
backgroundColor: '#fff',
31+
},
32+
},
33+
{
34+
dark: false,
35+
},
36+
);
37+
if (defaultIndentWithTab) {
38+
getExtensions.unshift(keymap.of([indentWithTab]));
39+
}
40+
if (defaultBasicSetup) {
41+
if (typeof defaultBasicSetup === 'boolean') {
42+
getExtensions.unshift(basicSetup());
43+
} else {
44+
getExtensions.unshift(basicSetup(defaultBasicSetup));
45+
}
46+
}
47+
if (placeholderStr) {
48+
getExtensions.unshift(placeholder(placeholderStr));
49+
}
50+
switch (theme) {
51+
case 'light':
52+
getExtensions.push(defaultLightThemeOption);
53+
break;
54+
case 'dark':
55+
getExtensions.push(oneDark);
56+
break;
57+
case 'none':
58+
break;
59+
default:
60+
getExtensions.push(theme);
61+
break;
62+
}
63+
if (editable === false) {
64+
getExtensions.push(EditorView.editable.of(false));
65+
}
66+
if (readOnly) {
67+
getExtensions.push(EditorState.readOnly.of(true));
68+
}
69+
70+
return [...getExtensions];
71+
};

core/src/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Statistics } from './utils';
77

88
export * from '@uiw/codemirror-extensions-basic-setup';
99
export * from './useCodeMirror';
10+
export * from './getDefaultExtensions';
1011
export * from './utils';
1112

1213
export interface ReactCodeMirrorProps
@@ -45,7 +46,7 @@ export interface ReactCodeMirrorProps
4546
*/
4647
readOnly?: boolean;
4748
/**
48-
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
49+
* Controls whether pressing the `Tab` key inserts a tab character and indents the text (`true`)
4950
* or behaves according to the browser's default behavior (`false`).
5051
* @default true
5152
*/

core/src/useCodeMirror.ts

Lines changed: 11 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { useEffect, useState } from 'react';
22
import { Annotation, EditorState, StateEffect } from '@codemirror/state';
3-
import { indentWithTab } from '@codemirror/commands';
4-
import { EditorView, keymap, ViewUpdate, placeholder } from '@codemirror/view';
5-
import { basicSetup } from '@uiw/codemirror-extensions-basic-setup';
6-
import { oneDark } from '@codemirror/theme-one-dark';
3+
import { EditorView, ViewUpdate } from '@codemirror/view';
4+
import { getDefaultExtensions } from './getDefaultExtensions';
75
import { getStatistics } from './utils';
86
import { ReactCodeMirrorProps } from '.';
97

@@ -41,16 +39,6 @@ export function useCodeMirror(props: UseCodeMirror) {
4139
const [container, setContainer] = useState<HTMLDivElement>();
4240
const [view, setView] = useState<EditorView>();
4341
const [state, setState] = useState<EditorState>();
44-
const defaultLightThemeOption = EditorView.theme(
45-
{
46-
'&': {
47-
backgroundColor: '#fff',
48-
},
49-
},
50-
{
51-
dark: false,
52-
},
53-
);
5442
const defaultThemeOption = EditorView.theme({
5543
'&': {
5644
height,
@@ -76,42 +64,16 @@ export function useCodeMirror(props: UseCodeMirror) {
7664
onStatistics && onStatistics(getStatistics(vu));
7765
});
7866

79-
let getExtensions = [updateListener, defaultThemeOption];
80-
if (defaultIndentWithTab) {
81-
getExtensions.unshift(keymap.of([indentWithTab]));
82-
}
83-
if (defaultBasicSetup) {
84-
if (typeof defaultBasicSetup === 'boolean') {
85-
getExtensions.unshift(basicSetup());
86-
} else {
87-
getExtensions.unshift(basicSetup(defaultBasicSetup));
88-
}
89-
}
90-
91-
if (placeholderStr) {
92-
getExtensions.unshift(placeholder(placeholderStr));
93-
}
94-
95-
switch (theme) {
96-
case 'light':
97-
getExtensions.push(defaultLightThemeOption);
98-
break;
99-
case 'dark':
100-
getExtensions.push(oneDark);
101-
break;
102-
case 'none':
103-
break;
104-
default:
105-
getExtensions.push(theme);
106-
break;
107-
}
67+
const defaultExtensions = getDefaultExtensions({
68+
theme,
69+
editable: true,
70+
readOnly: false,
71+
placeholder: placeholderStr,
72+
indentWithTab: defaultIndentWithTab,
73+
basicSetup: defaultBasicSetup,
74+
});
10875

109-
if (editable === false) {
110-
getExtensions.push(EditorView.editable.of(false));
111-
}
112-
if (readOnly) {
113-
getExtensions.push(EditorState.readOnly.of(true));
114-
}
76+
let getExtensions = [updateListener, defaultThemeOption, ...defaultExtensions];
11577

11678
if (onUpdate && typeof onUpdate === 'function') {
11779
getExtensions.push(EditorView.updateListener.of(onUpdate));

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"version": "4.19.11",
3-
"packages": ["themes/**", "core", "www"],
3+
"packages": ["themes/**", "core", "merge", "www"],
44
"useWorkspaces": true
55
}

merge/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!--rehype:ignore:start-->
2+
3+
# react-codemirror-merge
4+
5+
<!--rehype:ignore:end-->
6+
7+
[![npm version](https://img.shields.io/npm/v/react-codemirror-merge.svg)](https://www.npmjs.com/package/react-codemirror-merge)
8+
9+
CodeMirror merge view for React.
10+
11+
## Install
12+
13+
```bash
14+
npm install react-codemirror-merge --save
15+
```
16+
17+
## Usage
18+
19+
```jsx
20+
import CodeMirrorMerge from 'react-codemirror-merge';
21+
import { EditorView } from 'codemirror';
22+
import { EditorState } from '@codemirror/state';
23+
24+
const Original = CodeMirrorMerge.Original;
25+
const Modified = CodeMirrorMerge.Modified;
26+
let doc = `one
27+
two
28+
three
29+
four
30+
five`;
31+
32+
export const Example = () => {
33+
return (
34+
<CodeMirrorMerge>
35+
<Original value={doc} />
36+
<Modified
37+
value={doc.replace(/t/g, 'T') + 'Six'}
38+
extensions={[EditorView.editable.of(false), EditorState.readOnly.of(true)]}
39+
/>
40+
</CodeMirrorMerge>
41+
);
42+
};
43+
```
44+
45+
## Contributors
46+
47+
As always, thanks to our amazing contributors!
48+
49+
<a href="https://github.com/uiwjs/react-codemirror/graphs/contributors">
50+
<img src="https://uiwjs.github.io/react-codemirror/CONTRIBUTORS.svg" />
51+
</a>
52+
53+
Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).
54+
55+
## License
56+
57+
Licensed under the MIT License.

merge/package.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"name": "react-codemirror-merge",
3+
"version": "0.0.1",
4+
"description": "CodeMirror merge view for React.",
5+
"homepage": "https://uiwjs.github.io/react-codemirror",
6+
"author": "kenny wong <[email protected]>",
7+
"license": "MIT",
8+
"main": "./cjs/index.js",
9+
"module": "./esm/index.js",
10+
"scripts": {
11+
"watch": "tsbb watch src/*.tsx --use-babel",
12+
"build": "tsbb build src/*.tsx --use-babel",
13+
"test": "tsbb test --env=jsdom",
14+
"coverage": "tsbb test --env=jsdom --coverage --bail"
15+
},
16+
"repository": {
17+
"type": "git",
18+
"url": "https://github.com/uiwjs/react-codemirror.git"
19+
},
20+
"files": [
21+
"dist",
22+
"src",
23+
"esm",
24+
"cjs"
25+
],
26+
"peerDependencies": {
27+
"@babel/runtime": ">=7.11.0",
28+
"@codemirror/state": ">=6.0.0",
29+
"@codemirror/theme-one-dark": ">=6.0.0",
30+
"@codemirror/view": ">=6.0.0",
31+
"codemirror": ">=6.0.0",
32+
"react": ">=16.8.0",
33+
"react-dom": ">=16.8.0"
34+
},
35+
"dependencies": {
36+
"@babel/runtime": "^7.18.6",
37+
"@uiw/react-codemirror": "^4.19.11",
38+
"@codemirror/merge": "^6.0.1"
39+
},
40+
"keywords": [
41+
"react",
42+
"codemirror",
43+
"codemirror6",
44+
"react-codemirror",
45+
"editor",
46+
"syntax",
47+
"ide",
48+
"code"
49+
],
50+
"jest": {
51+
"coverageReporters": [
52+
"lcov",
53+
"json-summary"
54+
]
55+
}
56+
}

0 commit comments

Comments
 (0)