Skip to content
This repository was archived by the owner on Sep 14, 2022. It is now read-only.

Commit d09851b

Browse files
committed
feat: add Editor component
1 parent ba25993 commit d09851b

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

src/components/Editor.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React, { useState, useEffect, useRef } from "react";
2+
import CodeMirror from "codemirror";
3+
import type { FC } from "react";
4+
import type { Linter } from "eslint";
5+
import type { TextMarker, Editor as CodeEditor } from "codemirror";
6+
import "codemirror/lib/codemirror.css";
7+
import "codemirror/mode/javascript/javascript.js";
8+
import "@/css/editor.css";
9+
10+
interface Props {
11+
initial: string;
12+
onChange?: (text: string) => void;
13+
messages?: Linter.LintMessage[];
14+
}
15+
16+
const CODE_MIRROR_OPTIONS = {
17+
mode: "text/typescript",
18+
lineNumbers: true,
19+
showCursorWhenSelecting: true,
20+
matchBrackets: true,
21+
} as const;
22+
23+
let editor: CodeEditor | null = null;
24+
25+
export const Editor: FC<Props> = (props) => {
26+
const [text, setText] = useState<string>(props.initial);
27+
const [errorMarkers, setErrorMarkers] = useState<TextMarker[]>([]);
28+
const ref = useRef<HTMLTextAreaElement>(null);
29+
30+
useEffect(() => {
31+
if (ref.current) {
32+
editor = CodeMirror.fromTextArea(ref.current, CODE_MIRROR_OPTIONS);
33+
editor.on("change", () => {
34+
const value = editor?.getValue() ?? "";
35+
props.onChange?.(value);
36+
setText(value);
37+
});
38+
}
39+
}, []);
40+
41+
useEffect(() => {
42+
errorMarkers.forEach((marker) => marker.clear());
43+
if (props.messages && editor) {
44+
setErrorMarkers(
45+
props.messages?.map((message) => {
46+
const from = { line: message.line - 1, ch: message.column - 1 };
47+
const to = {
48+
line: (message.endLine || message.line) - 1,
49+
ch: (message.endColumn || message.column) - 1,
50+
};
51+
return (editor as CodeEditor).markText(from, to, {
52+
className: "editor-error",
53+
});
54+
})
55+
);
56+
}
57+
}, [props.messages]);
58+
59+
return (
60+
<div className="editor">
61+
<textarea id="code" readOnly autoComplete="off" ref={ref} value={text} />
62+
</div>
63+
);
64+
};

0 commit comments

Comments
 (0)