Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/editors/slate/slate-react/components/slate.tsx
1698 views
1
import React from "react";
2
import { useMemo, useState, useCallback, useEffect } from "react";
3
import { Descendant } from "slate";
4
5
import { ReactEditor } from "../plugin/react-editor";
6
import { FocusedContext } from "../hooks/use-focused";
7
import { EditorContext } from "../hooks/use-slate-static";
8
import { SlateContext } from "../hooks/use-slate";
9
import { EDITOR_TO_ON_CHANGE } from "../utils/weak-maps";
10
11
/**
12
* A wrapper around the provider to handle `onChange` events, because the editor
13
* is a mutable singleton so it won't ever register as "changed" otherwise.
14
*/
15
16
export const Slate = (props: {
17
editor: ReactEditor;
18
value: Descendant[];
19
children: React.ReactNode;
20
onChange: (value: Descendant[]) => void;
21
}) => {
22
const { editor, children, onChange, value, ...rest } = props;
23
const [ticks, setTick] = useState(0);
24
25
const context: [ReactEditor] = useMemo(() => {
26
editor.children = value;
27
editor.ticks = ticks;
28
Object.assign(editor, rest);
29
return [editor];
30
}, [ticks, value, ...Object.values(rest)]);
31
32
// We use a singleton object for the focused context..
33
// It turns out not doing this with these contexts makes slate
34
// **insanely slow** on large documents. Doing this, and it
35
// is VERY fast. It probably took over a month of my life to
36
// understand this, so please don't mess it up again!
37
const focused: { isFocused: boolean } = useMemo(() => {
38
return { isFocused: ReactEditor.isFocused(editor) };
39
}, []);
40
focused.isFocused = ReactEditor.isFocused(editor);
41
42
const onContextChange = useCallback(() => {
43
onChange(editor.children);
44
setTick(ticks + 1);
45
}, [ticks, onChange]);
46
47
EDITOR_TO_ON_CHANGE.set(editor, onContextChange);
48
49
useEffect(() => {
50
return () => {
51
EDITOR_TO_ON_CHANGE.set(editor, () => {});
52
};
53
}, []);
54
55
return (
56
<SlateContext.Provider value={context}>
57
<EditorContext.Provider value={editor}>
58
<FocusedContext.Provider value={focused}>
59
{children}
60
</FocusedContext.Provider>
61
</EditorContext.Provider>
62
</SlateContext.Provider>
63
);
64
};
65
66