67 lines
1.5 KiB
TypeScript
67 lines
1.5 KiB
TypeScript
import { onMount, onCleanup } from "solid-js";
|
|
import { EditorView, basicSetup } from "codemirror";
|
|
import { EditorState } from "@codemirror/state";
|
|
import { oneDark } from "@codemirror/theme-one-dark";
|
|
import { vim } from "@replit/codemirror-vim";
|
|
|
|
export interface EditorProps {
|
|
value: string,
|
|
onUpdate(val: string): void,
|
|
onRun(): void,
|
|
height?: string,
|
|
}
|
|
|
|
export function CodeEditor(props: EditorProps) {
|
|
let containerRef: HTMLDivElement | undefined;
|
|
let view: EditorView;
|
|
|
|
const handleKeydown = (e: KeyboardEvent) => {
|
|
if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
props.onRun();
|
|
}
|
|
};
|
|
|
|
onMount(() => {
|
|
const themeConfig = EditorView.theme({
|
|
"&": { height: props.height || "300px" },
|
|
".cm-scroller": { overflow: "auto" }
|
|
});
|
|
|
|
const state = EditorState.create({
|
|
doc: props.value,
|
|
extensions: [
|
|
basicSetup,
|
|
oneDark,
|
|
vim(),
|
|
themeConfig,
|
|
EditorView.updateListener.of((update) => {
|
|
if (update.docChanged) {
|
|
props.onUpdate(update.state.doc.toString());
|
|
}
|
|
}),
|
|
],
|
|
});
|
|
|
|
view = new EditorView({
|
|
state,
|
|
parent: containerRef!,
|
|
});
|
|
|
|
containerRef?.addEventListener("keydown", handleKeydown, { capture: true });
|
|
});
|
|
|
|
onCleanup(() => {
|
|
containerRef?.removeEventListener("keydown", handleKeydown, { capture: true });
|
|
view.destroy()
|
|
});
|
|
|
|
return (
|
|
<div
|
|
ref={containerRef}
|
|
class="editor-frame"
|
|
/>
|
|
);
|
|
}
|
|
|