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

Commit ab92434

Browse files
committed
feat: refactor editor
1 parent 8b42701 commit ab92434

File tree

5 files changed

+109
-72
lines changed

5 files changed

+109
-72
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useEffect } from "react";
22
import { Container, Row, Col, Tabs, Tab, Spinner } from "react-bootstrap";
3-
import { Editor } from "@/components/Editor";
3+
import { CodeEditor } from "@/components/CodeEditor";
44
import { RuleConfig } from "@/components/RuleConfig";
55
import { Messages } from "@/components/Messages";
66
import { Header } from "@/components/Header";
@@ -38,7 +38,7 @@ export const App: FC = () => {
3838
useEffect(() => {
3939
(async () => setLinter(await loadDemoLinter()))();
4040
}, []);
41-
41+
console.log(queryParamsState.get().code || DEFAULT_CODE);
4242
return (
4343
<>
4444
<Header />
@@ -47,7 +47,7 @@ export const App: FC = () => {
4747
<Col md={12}>
4848
<Tabs>
4949
<Tab eventKey="code" title="Code">
50-
<Editor
50+
<CodeEditor
5151
initial={queryParamsState.get().code || DEFAULT_CODE}
5252
onChange={(code) => {
5353
queryParamsState.set({ code, rules });

src/components/BaseEditor.tsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React, { useState, useEffect, useRef } from "react";
2+
import CodeMirror, { TextMarker } from "codemirror";
3+
import { EDITING_TIMEOUT } from "@/components/constants";
4+
import { debounce } from "@/shared/debounce";
5+
import type { FC } from "react";
6+
import type { Editor } from "codemirror";
7+
import "codemirror/lib/codemirror.css";
8+
import "codemirror/mode/javascript/javascript.js";
9+
import "@/css/editor.css";
10+
11+
export type Marker = [CodeMirror.Position, CodeMirror.Position];
12+
13+
interface Props {
14+
id: string;
15+
mode: "text/typescript" | "application/ld+json";
16+
markers?: Marker[];
17+
initial?: string;
18+
onChange?: (text: string) => void;
19+
}
20+
21+
const CODE_MIRROR_OPTIONS = {
22+
lineNumbers: true,
23+
showCursorWhenSelecting: true,
24+
matchBrackets: true,
25+
} as const;
26+
27+
export const BaseEditor: FC<Props> = (props) => {
28+
const [editor, setEditor] = useState<Editor | null>(null);
29+
const [text, setText] = useState<string>(props.initial ?? "");
30+
const [errorMarkers, setErrorMarkers] = useState<TextMarker[]>([]);
31+
const ref = useRef<HTMLTextAreaElement>(null);
32+
33+
useEffect(() => {
34+
if (ref.current) {
35+
const codeMirror = CodeMirror.fromTextArea(ref.current, {
36+
mode: props.mode,
37+
...CODE_MIRROR_OPTIONS,
38+
});
39+
setEditor(codeMirror);
40+
41+
codeMirror.on(
42+
"change",
43+
debounce(() => {
44+
const value = codeMirror.getValue();
45+
props.onChange?.(value);
46+
setText(value);
47+
}, EDITING_TIMEOUT)
48+
);
49+
}
50+
}, []);
51+
52+
useEffect(() => {
53+
errorMarkers.forEach((marker) => marker.clear());
54+
if (props.markers && editor) {
55+
setErrorMarkers(
56+
props.markers.map(([start, end]) =>
57+
editor.markText(start, end, {
58+
className: "editor-error",
59+
})
60+
)
61+
);
62+
}
63+
}, [props.markers, editor]);
64+
65+
return (
66+
<textarea
67+
id={props.id}
68+
readOnly
69+
autoComplete="off"
70+
ref={ref}
71+
value={text}
72+
/>
73+
);
74+
};

src/components/CodeEditor.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from "react";
2+
import { BaseEditor } from "@/components/BaseEditor";
3+
import type { Marker } from "@/components/BaseEditor";
4+
import type { FC } from "react";
5+
import type { Linter } from "eslint";
6+
7+
interface Props {
8+
initial: string;
9+
onChange?: (text: string) => void;
10+
messages?: Linter.LintMessage[];
11+
}
12+
13+
function messageToMarker(message: Linter.LintMessage): Marker {
14+
const from = { line: message.line - 1, ch: message.column - 1 };
15+
const to = {
16+
line: (message.endLine || message.line) - 1,
17+
ch: (message.endColumn || message.column) - 1,
18+
};
19+
return [from, to];
20+
}
21+
22+
export const CodeEditor: FC<Props> = (props) => (
23+
<div className="editor">
24+
<BaseEditor
25+
id="code"
26+
mode="text/typescript"
27+
initial={props.initial}
28+
markers={props.messages?.map(messageToMarker)}
29+
/>
30+
</div>
31+
);

src/components/Editor.tsx

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)