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]);