Skip to content

Commit

Permalink
feat(merge): add onChange props. (#502)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaywcjlove committed May 18, 2023
1 parent d48bb95 commit faf5b24
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 8 deletions.
4 changes: 4 additions & 0 deletions merge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ interface ModifiedProps {
[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;
}
```

Expand Down Expand Up @@ -146,6 +148,8 @@ interface OriginalProps {
[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;
}
```

Expand Down
25 changes: 22 additions & 3 deletions merge/src/Modified.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
import { useEffect } from 'react';
import { EditorStateConfig, Extension, StateEffect } from '@codemirror/state';
import { EditorStateConfig, Extension, StateEffect, Annotation } from '@codemirror/state';
import { getDefaultExtensions } from '@uiw/react-codemirror';
import { EditorView, ViewUpdate } from '@codemirror/view';
import { useStore } from './store';

const External = Annotation.define<boolean>();

export interface ModifiedProps extends Omit<EditorStateConfig, 'doc'> {
value?: EditorStateConfig['doc'];
extensions?: Extension[];
/** Fired whenever a change occurs to the document. */
onChange?(value: string, viewUpdate: ViewUpdate): void;
}

export const Modified = (props: ModifiedProps): JSX.Element | null => {
const { extensions = [] } = props;
const { extensions = [], onChange } = props;
const { modified, view, dispatch } = useStore();
const defaultExtensions = getDefaultExtensions();
useEffect(() => {
const data: EditorStateConfig = { extensions: [...defaultExtensions, ...extensions] };
const updateListener = EditorView.updateListener.of((vu: ViewUpdate) => {
if (
vu.docChanged &&
typeof onChange === 'function' &&
// Fix echoing of the remote changes:
// If transaction is market as remote we don't have to call `onChange` handler again
!vu.transactions.some((tr) => tr.annotation(External))
) {
const doc = vu.state.doc;
const value = doc.toString();
onChange(value, vu);
}
});
const data: EditorStateConfig = { extensions: [updateListener, ...defaultExtensions, ...extensions] };
if (modified?.doc !== props.value && view) {
data.doc = props.value;
dispatch!({ modified: { ...modified, ...data } });
Expand All @@ -22,6 +40,7 @@ export const Modified = (props: ModifiedProps): JSX.Element | null => {
view.b.dispatch({
changes: { from: 0, to: (modifiedDoc || '').length, insert: props.value || '' },
effects: StateEffect.appendConfig.of([...defaultExtensions, ...extensions]),
annotations: [External.of(true)],
});
}
}
Expand Down
26 changes: 22 additions & 4 deletions merge/src/Original.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
import { useEffect } from 'react';
import { EditorStateConfig, Extension, StateEffect } from '@codemirror/state';
import { useStore } from './store';
import { EditorStateConfig, Extension, StateEffect, Annotation } from '@codemirror/state';
import { EditorView, ViewUpdate } from '@codemirror/view';
import { getDefaultExtensions } from '@uiw/react-codemirror';
import { useStore } from './store';

const External = Annotation.define<boolean>();

export interface OriginalProps extends Omit<EditorStateConfig, 'doc'> {
value?: EditorStateConfig['doc'];
extensions?: Extension[];
/** Fired whenever a change occurs to the document. */
onChange?(value: string, viewUpdate: ViewUpdate): void;
}

export const Original = (props: OriginalProps): JSX.Element | null => {
const { extensions = [] } = props;
const { extensions = [], onChange } = props;
const { original, view, dispatch } = useStore();
const defaultExtensions = getDefaultExtensions();
useEffect(() => {
const data: EditorStateConfig = { extensions: [...defaultExtensions, ...extensions] };
const updateListener = EditorView.updateListener.of((vu: ViewUpdate) => {
if (
vu.docChanged &&
typeof onChange === 'function' &&
// Fix echoing of the remote changes:
// If transaction is market as remote we don't have to call `onChange` handler again
!vu.transactions.some((tr) => tr.annotation(External))
) {
const doc = vu.state.doc;
const value = doc.toString();
onChange(value, vu);
}
});
const data: EditorStateConfig = { extensions: [updateListener, ...defaultExtensions, ...extensions] };
if (original?.doc !== props.value && view) {
data.doc = props.value;
dispatch!({ original: { ...original, ...data } });
Expand Down
3 changes: 2 additions & 1 deletion www/src/pages/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ const hyperlink: {
}[] = [
{
href: 'https://www.npmjs.com/package/@uiw/react-codemirror',
label: 'View On NPM',
label: 'On NPM',
},
{
href: 'https://codemirror.net/docs/',
Expand Down Expand Up @@ -150,6 +150,7 @@ export default function App() {
<Link to="/extensions" className="extensions">
Extensions
</Link>
<Link to="/merge/document">Merge</Link>
{hyperlink.map(({ href, label, style }, idx) => {
return (
<a key={idx} target="_blank" rel="noopener noreferrer" href={href} style={style}>
Expand Down

0 comments on commit faf5b24

Please sign in to comment.