fluent-pad/client/src/components/CollaborativeEditor.tsx
2021-09-10 02:04:29 +03:00

79 lines
2.3 KiB
TypeScript

import _ from 'lodash';
import { useEffect, useState } from 'react';
import { getUpdatedDocFromText, initDoc, SyncClient } from '../app/sync';
import { withErrorHandlingAsync } from './util';
import { addEntry, getHistory, registerTextState } from 'src/_aqua/app';
const broadcastUpdates = _.debounce((text: string, syncClient: SyncClient) => {
let doc = syncClient.getDoc();
if (doc) {
let newDoc = getUpdatedDocFromText(doc, text);
syncClient.syncDoc(newDoc);
}
}, 100);
export const CollaborativeEditor = () => {
const [text, setText] = useState<string | null>(null);
const [syncClient, setSyncClient] = useState(new SyncClient());
useEffect(() => {
syncClient.handleDocUpdate = (doc) => {
setText(doc.text.toString());
};
syncClient.handleSendChanges = (changes: string) => {
withErrorHandlingAsync(async () => {
const res = await addEntry(changes);
if (res.ret_code !== 0) {
throw new Error(
`Failed to add message to history service, code=${res.ret_code}, message=${res.err_msg}`,
);
}
});
};
registerTextState({
notifyTextUpdate: (changes, isAuthorized) => {
if (changes) {
syncClient.receiveChanges(changes);
}
}
})
syncClient.start();
// don't block
withErrorHandlingAsync(async () => {
const res = await getHistory();
for (let e of res.entries) {
syncClient.receiveChanges(e.body);
}
if (syncClient.getDoc() === undefined) {
syncClient.syncDoc(initDoc());
}
});
return () => {
syncClient.stop();
};
}, []);
const handleTextUpdate = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
const newText = e.target.value;
setText(newText);
broadcastUpdates(newText, syncClient);
};
return (
<textarea
spellCheck={false}
className="code-editor"
disabled={text === null}
value={text ?? ''}
onChange={handleTextUpdate}
/>
);
};