From 7637bff75321ca219d589ab688a1be9e3432cae9 Mon Sep 17 00:00:00 2001
From: Ivan Buryak <11bit@users.noreply.github.com>
Date: Thu, 9 Feb 2023 16:42:59 +0500
Subject: [PATCH] fix: Fix echo `onChange` call when value prop is changed
(#456)
---
core/src/__tests__/index.test.tsx | 7 +++++++
core/src/useCodeMirror.ts | 13 +++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/core/src/__tests__/index.test.tsx b/core/src/__tests__/index.test.tsx
index b501fdaf2..bce264810 100644
--- a/core/src/__tests__/index.test.tsx
+++ b/core/src/__tests__/index.test.tsx
@@ -85,3 +85,10 @@ it('CodeMirror editable', async () => {
expect(text.className).toEqual('cm-content');
expect(text.tagName).toEqual('DIV');
});
+
+it("CodeMirror doesn't echo changes", async () => {
+ const handleChange = jest.fn();
+ const { rerender } = render();
+ rerender();
+ expect(handleChange).not.toHaveBeenCalled();
+});
diff --git a/core/src/useCodeMirror.ts b/core/src/useCodeMirror.ts
index f697505fd..4b9a84723 100644
--- a/core/src/useCodeMirror.ts
+++ b/core/src/useCodeMirror.ts
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
-import { EditorState, StateEffect } from '@codemirror/state';
+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';
@@ -7,6 +7,8 @@ import { oneDark } from '@codemirror/theme-one-dark';
import { getStatistics } from './utils';
import { ReactCodeMirrorProps } from '.';
+const External = Annotation.define();
+
export interface UseCodeMirror extends ReactCodeMirrorProps {
container?: HTMLDivElement | null;
}
@@ -60,7 +62,13 @@ export function useCodeMirror(props: UseCodeMirror) {
},
});
const updateListener = EditorView.updateListener.of((vu: ViewUpdate) => {
- if (vu.docChanged && typeof onChange === 'function') {
+ 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);
@@ -188,6 +196,7 @@ export function useCodeMirror(props: UseCodeMirror) {
if (view && value !== currentValue) {
view.dispatch({
changes: { from: 0, to: currentValue.length, insert: value || '' },
+ annotations: [External.of(true)],
});
}
}, [value, view]);