Skip to content

Commit 2a3efaf

Browse files
committedJun 5, 2023
fix: fix Original/Modified props issue. (#515)
1 parent 8a5c149 commit 2a3efaf

File tree

5 files changed

+96
-28
lines changed

5 files changed

+96
-28
lines changed
 

‎merge/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,33 @@ export const Example = () => {
7676
};
7777
```
7878

79+
```jsx
80+
import React, { useState } from 'react';
81+
import CodeMirrorMerge from 'react-codemirror-merge';
82+
import { EditorView } from '@codemirror/view';
83+
import { javascript } from '@codemirror/lang-javascript';
84+
import { githubLight, githubDark } from '@uiw/codemirror-theme-github';
85+
86+
const Original = CodeMirrorMerge.Original;
87+
const Modified = CodeMirrorMerge.Modified;
88+
let doc = `function examle() {
89+
90+
}`;
91+
92+
function Example() {
93+
const [theme, setTheme] = useState('light');
94+
return (
95+
<div>
96+
<CodeMirrorMerge theme={theme === 'light' ? githubLight : githubDark} orientation="a-b">
97+
<Original extensions={[javascript({ jsx: true }), EditorView.lineWrapping]} value={doc} />
98+
<Modified extensions={[EditorView.lineWrapping, javascript({ jsx: true })]} value={doc.replace(/e/g, 'T')} />
99+
</CodeMirrorMerge>
100+
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Change Theme {theme}</button>
101+
</div>
102+
);
103+
}
104+
```
105+
79106
## Props
80107

81108
```ts

‎merge/src/Internal.tsx

+14-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,20 @@ export const Internal = React.forwardRef<InternalRef, CodeMirrorMergeProps>((pro
5050
if (view && original && modified && theme && editor.current && dispatch) {
5151
editor.current.innerHTML = '';
5252
new MergeView({
53-
a: { ...original, extensions: [...(originalExtension || []), ...getDefaultExtensions({ theme: theme })] },
54-
b: { ...modified, extensions: [...(modifiedExtension || []), ...getDefaultExtensions({ theme: theme })] },
53+
a: {
54+
...original,
55+
extensions: [
56+
...(originalExtension?.extension || []),
57+
...getDefaultExtensions({ ...originalExtension?.option, theme }),
58+
],
59+
},
60+
b: {
61+
...modified,
62+
extensions: [
63+
...(modifiedExtension?.extension || []),
64+
...getDefaultExtensions({ ...modifiedExtension?.option, theme }),
65+
],
66+
},
5567
parent: editor.current,
5668
...opts,
5769
});

‎merge/src/Modified.tsx

+23-13
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ export interface ModifiedProps extends Omit<DefaultExtensionsOptions, 'theme'>,
1414
}
1515

1616
export const Modified = (props: ModifiedProps): JSX.Element | null => {
17-
const { extensions = [], selection, onChange, ...otherOption } = props;
17+
const { extensions = [], value, selection, onChange, ...otherOption } = props;
1818
const { modified, view, theme, dispatch } = useStore();
19-
const defaultExtensions = getDefaultExtensions({ ...otherOption, theme });
19+
const defaultExtensionsOptions = { ...otherOption };
20+
const defaultExtensions = getDefaultExtensions({ ...defaultExtensionsOptions, theme });
2021
const updateListener = EditorView.updateListener.of((vu: ViewUpdate) => {
2122
if (
2223
vu.docChanged &&
@@ -26,40 +27,49 @@ export const Modified = (props: ModifiedProps): JSX.Element | null => {
2627
!vu.transactions.some((tr) => tr.annotation(External))
2728
) {
2829
const doc = vu.state.doc;
29-
const value = doc.toString();
30-
onChange(value, vu);
30+
const val = doc.toString();
31+
onChange(val, vu);
3132
}
3233
});
3334
const extensionsData = [updateListener, ...defaultExtensions, ...extensions];
3435
const data: EditorStateConfig = { extensions: [...extensionsData] };
3536

3637
useEffect(() => {
3738
dispatch!({
38-
modified: { doc: props.value, selection: selection, ...data },
39-
modifiedExtension: [updateListener, extensions],
39+
modified: { doc: value, selection: selection, ...data },
40+
modifiedExtension: {
41+
option: defaultExtensionsOptions,
42+
extension: [updateListener, extensions],
43+
},
4044
});
4145
}, []);
4246

43-
useEffect(() => dispatch!({ modifiedExtension: [updateListener, extensions] }), [extensions]);
47+
useEffect(
48+
() =>
49+
dispatch!({
50+
modifiedExtension: { option: otherOption, extension: [updateListener, extensions] },
51+
}),
52+
[props],
53+
);
4454

4555
useEffect(() => {
46-
if (modified?.doc !== props.value && view) {
47-
data.doc = props.value;
48-
dispatch!({ modified: { ...modified, ...data } });
56+
if (modified?.doc !== value && view) {
57+
data.doc = value;
4958
const modifiedDoc = view?.b.state.doc.toString();
50-
if (modifiedDoc !== props.value) {
59+
if (modifiedDoc !== value) {
5160
view.b.dispatch({
52-
changes: { from: 0, to: (modifiedDoc || '').length, insert: props.value || '' },
61+
changes: { from: 0, to: (modifiedDoc || '').length, insert: value || '' },
5362
effects: StateEffect.reconfigure.of([...extensionsData]),
5463
annotations: [External.of(true)],
5564
});
5665
}
66+
dispatch!({ modified: { ...modified, ...data } });
5767
}
5868
if (modified?.selection !== selection) {
5969
data.selection = selection;
6070
dispatch!({ modified: { ...modified, ...data } });
6171
}
62-
}, [props.value, extensions, selection, view]);
72+
}, [value, extensions, selection, view]);
6373

6474
return null;
6575
};

‎merge/src/Original.tsx

+23-11
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export interface OriginalProps extends Omit<DefaultExtensionsOptions, 'theme'>,
1414
}
1515

1616
export const Original = (props: OriginalProps): JSX.Element | null => {
17-
const { extensions = [], selection, onChange, ...otherOption } = props;
17+
const { extensions = [], value, selection, onChange, ...otherOption } = props;
1818
const { original, view, theme, dispatch } = useStore();
1919
const defaultExtensions = getDefaultExtensions({ ...otherOption, theme });
2020
const updateListener = EditorView.updateListener.of((vu: ViewUpdate) => {
@@ -26,30 +26,42 @@ export const Original = (props: OriginalProps): JSX.Element | null => {
2626
!vu.transactions.some((tr) => tr.annotation(External))
2727
) {
2828
const doc = vu.state.doc;
29-
const value = doc.toString();
30-
onChange(value, vu);
29+
const val = doc.toString();
30+
onChange(val, vu);
3131
}
3232
});
3333
const extensionsData = [updateListener, ...defaultExtensions, ...extensions];
3434
const data: EditorStateConfig = { extensions: [...extensionsData] };
3535

3636
useEffect(() => {
3737
dispatch!({
38-
original: { doc: props.value, selection: selection, ...data },
39-
modifiedExtension: [updateListener, extensions],
38+
original: { doc: value, selection: selection, ...data },
39+
originalExtension: {
40+
option: otherOption,
41+
extension: [updateListener, extensions],
42+
},
4043
});
4144
}, []);
4245

43-
useEffect(() => dispatch!({ originalExtension: [updateListener, extensions] }), [extensions]);
46+
useEffect(
47+
() =>
48+
dispatch!({
49+
originalExtension: {
50+
option: otherOption,
51+
extension: [updateListener, extensions],
52+
},
53+
}),
54+
[props],
55+
);
4456

4557
useEffect(() => {
46-
if (original?.doc !== props.value && view) {
47-
data.doc = props.value;
58+
if (original?.doc !== value && view) {
59+
data.doc = value;
4860
dispatch!({ original: { ...original, ...data } });
4961
const originalDoc = view?.a.state.doc.toString();
50-
if (originalDoc !== props.value) {
62+
if (originalDoc !== value) {
5163
view?.a.dispatch({
52-
changes: { from: 0, to: (originalDoc || '').length, insert: props.value || '' },
64+
changes: { from: 0, to: (originalDoc || '').length, insert: value || '' },
5365
effects: StateEffect.reconfigure.of([...extensionsData]),
5466
annotations: [External.of(true)],
5567
});
@@ -59,7 +71,7 @@ export const Original = (props: OriginalProps): JSX.Element | null => {
5971
data.selection = selection;
6072
dispatch!({ original: { ...original, ...data } });
6173
}
62-
}, [props.value, selection, view]);
74+
}, [value, selection, view]);
6375

6476
return null;
6577
};

‎merge/src/store.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,22 @@ import React, { PropsWithChildren, createContext, useContext, useEffect, useRedu
22
import { EditorStateConfig } from '@codemirror/state';
33
import { MergeView, MergeConfig } from '@codemirror/merge';
44
import { Extension } from '@codemirror/state';
5+
import { DefaultExtensionsOptions } from '@uiw/react-codemirror';
56

67
export interface StoreContextValue extends InitialState {
78
dispatch?: React.Dispatch<InitialState>;
89
}
910

1011
export interface InitialState extends MergeConfig {
11-
modifiedExtension?: Extension[];
12+
modifiedExtension?: {
13+
option: Omit<DefaultExtensionsOptions, 'theme'>;
14+
extension: Extension[];
15+
};
1216
modified?: EditorStateConfig;
13-
originalExtension?: Extension[];
17+
originalExtension?: {
18+
option: Omit<DefaultExtensionsOptions, 'theme'>;
19+
extension: Extension[];
20+
};
1421
original?: EditorStateConfig;
1522
view?: MergeView;
1623
theme?: 'light' | 'dark' | 'none' | Extension;

0 commit comments

Comments
 (0)
Please sign in to comment.