From 6953ea2210d22309c358dd5be0c1901818b4cc74 Mon Sep 17 00:00:00 2001 From: Hackerwins Date: Wed, 3 Aug 2022 13:48:22 +0900 Subject: [PATCH 1/2] Bump up Yorkie to v0.2.14 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a7e1331..603ddaea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "redux": "^4.0.5", "redux-thunk": "^2.3.0", "typescript": "^3.7.5", - "yorkie-js-sdk": "^0.2.12" + "yorkie-js-sdk": "^0.2.14" }, "engines": { "node": ">=16.0.0", @@ -25293,9 +25293,9 @@ } }, "node_modules/yorkie-js-sdk": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.2.12.tgz", - "integrity": "sha512-Sx+JPfBUmBTotta0Mw7cl6jT2G2+Z1tdKBGchTPCQ0xWA1zT9rj56wmRGSIdZpoKLzZ6HTuAv1lTS1rKLyZNgg==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.2.14.tgz", + "integrity": "sha512-/AcS1v35ItwruZJTeSKOxsl1SSFgS7YHfVAkLe+sENWj5XvpvKqYBgrya1FPCzrLnbZZ99ZZa8lpiPg+EJ89mQ==", "dependencies": { "@types/google-protobuf": "^3.15.5", "@types/long": "^4.0.1", @@ -46376,9 +46376,9 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" }, "yorkie-js-sdk": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.2.12.tgz", - "integrity": "sha512-Sx+JPfBUmBTotta0Mw7cl6jT2G2+Z1tdKBGchTPCQ0xWA1zT9rj56wmRGSIdZpoKLzZ6HTuAv1lTS1rKLyZNgg==", + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.2.14.tgz", + "integrity": "sha512-/AcS1v35ItwruZJTeSKOxsl1SSFgS7YHfVAkLe+sENWj5XvpvKqYBgrya1FPCzrLnbZZ99ZZa8lpiPg+EJ89mQ==", "requires": { "@types/google-protobuf": "^3.15.5", "@types/long": "^4.0.1", diff --git a/package.json b/package.json index 564e42be..82630017 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "redux": "^4.0.5", "redux-thunk": "^2.3.0", "typescript": "^3.7.5", - "yorkie-js-sdk": "^0.2.12" + "yorkie-js-sdk": "^0.2.14" }, "scripts": { "start": "REACT_APP_GIT_HASH=`git rev-parse --short HEAD` react-scripts start", From 43d973a05111c15271f4806ca6e3b4a25b6af0c7 Mon Sep 17 00:00:00 2001 From: Hackerwins Date: Thu, 4 Aug 2022 13:17:42 +0900 Subject: [PATCH 2/2] Fix a bug that handlers were attached twice when changing the theme --- src/components/Editor/CodeEditor/index.tsx | 214 +++++++++++---------- 1 file changed, 108 insertions(+), 106 deletions(-) diff --git a/src/components/Editor/CodeEditor/index.tsx b/src/components/Editor/CodeEditor/index.tsx index 086f2b6d..af964bb1 100644 --- a/src/components/Editor/CodeEditor/index.tsx +++ b/src/components/Editor/CodeEditor/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useRef, useCallback } from 'react'; +import React, { useEffect, useMemo, useRef, useCallback, useState } from 'react'; import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; import { useSelector } from 'react-redux'; import { ActorID, DocEvent, TextChange } from 'yorkie-js-sdk'; @@ -82,6 +82,7 @@ export default function CodeEditor({ forwardedRef }: CodeEditorProps) { const client = useSelector((state: AppState) => state.docState.client); const peers = useSelector((state: AppState) => state.peerState.peers); const cursorMapRef = useRef>(new Map()); + const [editor, setEditor] = useState(null); const connectCursor = useCallback((clientID: ActorID, metadata: Metadata) => { cursorMapRef.current.set(clientID, new Cursor(clientID, metadata)); @@ -94,128 +95,129 @@ export default function CodeEditor({ forwardedRef }: CodeEditorProps) { } }, []); - const getCmInstanceCallback = useCallback( - (editor: CodeMirror.Editor) => { - if (!client || !doc) { - return; - } - - // eslint-disable-next-line no-param-reassign - forwardedRef.current = editor; - - const updateCursor = (clientID: ActorID, pos: CodeMirror.Position) => { - const cursor = cursorMapRef.current.get(clientID); - cursor?.updateCursor(editor, pos); - }; - - const updateLine = (clientID: ActorID, fromPos: CodeMirror.Position, toPos: CodeMirror.Position) => { - const cursor = cursorMapRef.current.get(clientID); - cursor?.updateLine(editor, fromPos, toPos); - }; + const getCmInstanceCallback = useCallback((cm: CodeMirror.Editor) => { + setEditor(cm); + }, []); - let syncText = () => {}; + useEffect(() => { + for (const [id, peer] of Object.entries(peers)) { + if (cursorMapRef.current.has(id) && peer.status === ConnectionStatus.Disconnected) { + disconnectCursor(id); + } else if (!cursorMapRef.current.has(id) && peer.status === ConnectionStatus.Connected) { + connectCursor(id, peer.metadata); + } + } + }, [peers]); - doc.subscribe((event: DocEvent) => { - if (event.type === 'remote-change') { - // display remote cursors - for (const { change } of event.value) { - const actor = change.getID().getActorID()!; - if (actor !== client.getID()) { - if (!cursorMapRef.current.has(actor)) { - return; - } + useEffect(() => { + if (!client || !doc || !editor) { + return; + } - const cursor = cursorMapRef.current.get(actor); - if (cursor!.isActive()) { - return; - } + // eslint-disable-next-line no-param-reassign + forwardedRef.current = editor; + + const updateCursor = (clientID: ActorID, pos: CodeMirror.Position) => { + const cursor = cursorMapRef.current.get(clientID); + cursor?.updateCursor(editor, pos); + }; + + const updateLine = (clientID: ActorID, fromPos: CodeMirror.Position, toPos: CodeMirror.Position) => { + const cursor = cursorMapRef.current.get(clientID); + cursor?.updateLine(editor, fromPos, toPos); + }; + + let syncText = () => {}; + + doc.subscribe((event: DocEvent) => { + if (event.type === 'remote-change') { + // display remote cursors + for (const { change } of event.value) { + const actor = change.getID().getActorID()!; + if (actor !== client.getID()) { + if (!cursorMapRef.current.has(actor)) { + return; + } - updateCursor(actor, editor.posFromIndex(0)); + const cursor = cursorMapRef.current.get(actor); + if (cursor!.isActive()) { + return; } + + updateCursor(actor, editor.posFromIndex(0)); } - } else if (event.type === 'snapshot') { - // re-sync for the new text from the snapshot - syncText(); } - }); + } else if (event.type === 'snapshot') { + // re-sync for the new text from the snapshot + syncText(); + } + }); - // local to remote - editor.on('beforeChange', (instance: CodeMirror.Editor, change: CodeMirror.EditorChange) => { - if (change.origin === 'yorkie' || change.origin === 'setValue') { - return; - } + // local to remote + editor.on('beforeChange', (instance: CodeMirror.Editor, change: CodeMirror.EditorChange) => { + if (change.origin === 'yorkie' || change.origin === 'setValue') { + return; + } - const from = editor.indexFromPos(change.from); - const to = editor.indexFromPos(change.to); - const content = change.text.join('\n'); + const from = editor.indexFromPos(change.from); + const to = editor.indexFromPos(change.to); + const content = change.text.join('\n'); - doc.update((root) => { - root.content.edit(from, to, content); - }); + doc.update((root) => { + root.content.edit(from, to, content); }); + }); - editor.on('beforeSelectionChange', (instance: CodeMirror.Editor, data: CodeMirror.EditorSelectionChange) => { - if (!data.origin) { - return; - } + editor.on('beforeSelectionChange', (instance: CodeMirror.Editor, data: CodeMirror.EditorSelectionChange) => { + if (!data.origin) { + return; + } - const from = editor.indexFromPos(data.ranges[0].anchor); - const to = editor.indexFromPos(data.ranges[0].head); + const from = editor.indexFromPos(data.ranges[0].anchor); + const to = editor.indexFromPos(data.ranges[0].head); - doc.update((root) => { - root.content.select(from, to); - }); + doc.update((root) => { + root.content.select(from, to); }); - - // remote to local - const changeEventHandler = (changes: TextChange[]) => { - changes.forEach((change) => { - const { actor, from, to } = change; - if (change.type === 'content') { - const content = change.content || ''; - if (actor !== client.getID()) { - const fromPos = editor.posFromIndex(from); - const toPos = editor.posFromIndex(to); - editor.replaceRange(content, fromPos, toPos, 'yorkie'); - } - } else if (change.type === 'selection') { - if (actor !== client.getID()) { - let fromPos = editor.posFromIndex(from); - let toPos = editor.posFromIndex(to); - updateCursor(actor, toPos); - if (from > to) { - [toPos, fromPos] = [fromPos, toPos]; - } - updateLine(actor, fromPos, toPos); + }); + + // remote to local + const changeEventHandler = (changes: TextChange[]) => { + changes.forEach((change) => { + const { actor, from, to } = change; + if (change.type === 'content') { + const content = change.content || ''; + if (actor !== client.getID()) { + const fromPos = editor.posFromIndex(from); + const toPos = editor.posFromIndex(to); + editor.replaceRange(content, fromPos, toPos, 'yorkie'); + } + } else if (change.type === 'selection') { + if (actor !== client.getID()) { + let fromPos = editor.posFromIndex(from); + let toPos = editor.posFromIndex(to); + updateCursor(actor, toPos); + if (from > to) { + [toPos, fromPos] = [fromPos, toPos]; } + updateLine(actor, fromPos, toPos); } - }); - }; - - // sync text of document and editor - syncText = () => { - const text = doc.getRoot().content; - text.onChanges(changeEventHandler); - editor.setValue(text.toString()); - }; - syncText(); - editor.addKeyMap(menu.codeKeyMap); - editor.setOption('keyMap', menu.codeKeyMap); - editor.getDoc().clearHistory(); - editor.focus(); - }, - [client, doc, menu], - ); - - useEffect(() => { - for (const [id, peer] of Object.entries(peers)) { - if (cursorMapRef.current.has(id) && peer.status === ConnectionStatus.Disconnected) { - disconnectCursor(id); - } else if (!cursorMapRef.current.has(id) && peer.status === ConnectionStatus.Connected) { - connectCursor(id, peer.metadata); - } - } - }, [peers]); + } + }); + }; + + // sync text of document and editor + syncText = () => { + const text = doc.getRoot().content; + text.onChanges(changeEventHandler); + editor.setValue(text.toString()); + }; + syncText(); + editor.addKeyMap(menu.codeKeyMap); + editor.setOption('keyMap', menu.codeKeyMap); + editor.getDoc().clearHistory(); + editor.focus(); + }, [editor]); const options = useMemo(() => { const opts = {