|
1 | 1 | import { Box } from "@hope-ui/solid"
|
2 |
| -import { createEffect, createSignal, onCleanup, onMount } from "solid-js" |
3 |
| -import { MaybeLoading } from "./FullLoading" |
4 |
| -import loader from "@monaco-editor/loader" |
5 |
| -import { monaco_cdn } from "~/utils" |
| 2 | +import { createEffect, onCleanup, onMount, splitProps } from "solid-js" |
| 3 | +import * as monaco from "monaco-editor" |
6 | 4 |
|
7 |
| -loader.config({ |
8 |
| - paths: { |
9 |
| - vs: monaco_cdn, |
| 5 | +// Configure worker for Monaco Editor |
| 6 | +import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker" |
| 7 | +import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker" |
| 8 | +import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker" |
| 9 | +import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker" |
| 10 | +import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker" |
| 11 | + |
| 12 | +self.MonacoEnvironment = { |
| 13 | + getWorker(_, label) { |
| 14 | + if (label === "json") { |
| 15 | + return new jsonWorker() |
| 16 | + } |
| 17 | + if (label === "css" || label === "scss" || label === "less") { |
| 18 | + return new cssWorker() |
| 19 | + } |
| 20 | + if (label === "html" || label === "handlebars" || label === "razor") { |
| 21 | + return new htmlWorker() |
| 22 | + } |
| 23 | + if (label === "typescript" || label === "javascript") { |
| 24 | + return new tsWorker() |
| 25 | + } |
| 26 | + return new editorWorker() |
10 | 27 | },
|
11 |
| -}) |
12 |
| -export interface MonacoEditorProps { |
| 28 | +} |
| 29 | +export interface MonacoEditorProps |
| 30 | + extends monaco.editor.IStandaloneEditorConstructionOptions { |
13 | 31 | value: string
|
14 | 32 | onChange?: (value: string) => void
|
15 |
| - theme: "vs" | "vs-dark" |
| 33 | + theme?: "vs" | "vs-dark" | "hc-black" | "hc-light" |
16 | 34 | path?: string
|
17 | 35 | language?: string
|
18 | 36 | }
|
19 |
| -let monaco: any |
20 |
| - |
21 |
| -export const MonacoEditorLoader = (props: MonacoEditorProps) => { |
22 |
| - const [loading, setLoading] = createSignal(true) |
23 |
| - loader.init().then((m) => { |
24 |
| - monaco = m |
25 |
| - setLoading(false) |
26 |
| - }) |
27 |
| - return ( |
28 |
| - <MaybeLoading loading={loading()}> |
29 |
| - <MonacoEditor {...props} /> |
30 |
| - </MaybeLoading> |
31 |
| - ) |
32 |
| -} |
33 | 37 |
|
34 | 38 | export const MonacoEditor = (props: MonacoEditorProps) => {
|
35 | 39 | let monacoEditorDiv: HTMLDivElement
|
36 |
| - let monacoEditor: any /*monaco.editor.IStandaloneCodeEditor*/ |
37 |
| - let model: any /*monaco.editor.ITextModel*/ |
| 40 | + let monacoEditor: monaco.editor.IStandaloneCodeEditor |
| 41 | + let model: monaco.editor.ITextModel |
| 42 | + |
| 43 | + // Separate custom properties and Monaco options |
| 44 | + const [customProps, monacoOptions] = splitProps(props, ["onChange", "path"]) |
| 45 | + |
38 | 46 | onMount(() => {
|
39 | 47 | monacoEditor = monaco.editor.create(monacoEditorDiv!, {
|
40 |
| - value: props.value, |
41 |
| - theme: props.theme, |
| 48 | + automaticLayout: true, |
| 49 | + ...monacoOptions, |
42 | 50 | })
|
| 51 | + |
43 | 52 | model = monaco.editor.createModel(
|
44 | 53 | props.value,
|
45 | 54 | props.language,
|
46 |
| - props.path ? monaco.Uri.parse(props.path) : undefined, |
| 55 | + customProps.path ? monaco.Uri.parse(customProps.path) : undefined, |
47 | 56 | )
|
48 | 57 | monacoEditor.setModel(model)
|
| 58 | + |
49 | 59 | monacoEditor.onDidChangeModelContent(() => {
|
50 |
| - props.onChange?.(monacoEditor.getValue()) |
| 60 | + customProps.onChange?.(monacoEditor.getValue()) |
51 | 61 | })
|
52 | 62 | })
|
| 63 | + |
53 | 64 | createEffect(() => {
|
54 |
| - monacoEditor.setValue(props.value) |
| 65 | + if (monacoEditor && props.value !== monacoEditor.getValue()) { |
| 66 | + monacoEditor.setValue(props.value) |
| 67 | + } |
55 | 68 | })
|
56 | 69 |
|
57 | 70 | createEffect(() => {
|
58 |
| - monaco.editor.setTheme(props.theme) |
| 71 | + if (monacoEditor && props.theme) { |
| 72 | + monaco.editor.setTheme(props.theme) |
| 73 | + } |
59 | 74 | })
|
| 75 | + |
60 | 76 | onCleanup(() => {
|
61 |
| - model && model.dispose() |
62 |
| - monacoEditor && monacoEditor.dispose() |
| 77 | + model?.dispose() |
| 78 | + monacoEditor?.dispose() |
63 | 79 | })
|
| 80 | + |
64 | 81 | return <Box w="$full" h="70vh" ref={monacoEditorDiv!} />
|
65 | 82 | }
|
0 commit comments