| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 | 
							- import Editor, { Monaco } from "@monaco-editor/react"
 - import useTheme from "hooks/useTheme"
 - import prettier from "prettier/standalone"
 - import parserTypeScript from "prettier/parser-typescript"
 - import codeAsString from "./code-as-string"
 - import React, { useCallback, useEffect, useRef } from "react"
 - import styled from "styles"
 - import { IMonaco, IMonacoEditor } from "types"
 - 
 - interface Props {
 -   value: string
 -   error: { line: number }
 -   fontSize: number
 -   monacoRef?: React.MutableRefObject<IMonaco>
 -   editorRef?: React.MutableRefObject<IMonacoEditor>
 -   readOnly?: boolean
 -   onMount?: (value: string, editor: IMonacoEditor) => void
 -   onUnmount?: (editor: IMonacoEditor) => void
 -   onChange?: (value: string, editor: IMonacoEditor) => void
 -   onSave?: (value: string, editor: IMonacoEditor) => void
 -   onError?: (error: Error, line: number, col: number) => void
 -   onKey?: () => void
 - }
 - 
 - export default function CodeEditor({
 -   editorRef,
 -   monacoRef,
 -   fontSize,
 -   value,
 -   error,
 -   readOnly,
 -   onChange,
 -   onSave,
 -   onKey,
 - }: Props) {
 -   const { theme } = useTheme()
 -   const rEditor = useRef<IMonacoEditor>(null)
 -   const rMonaco = useRef<IMonaco>(null)
 - 
 -   const handleBeforeMount = useCallback((monaco: Monaco) => {
 -     if (monacoRef) {
 -       monacoRef.current = monaco
 -     }
 -     rMonaco.current = monaco
 - 
 -     monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
 -       allowJs: true,
 -       checkJs: false,
 -       strict: false,
 -       noLib: true,
 -       lib: ["es6"],
 -       target: monaco.languages.typescript.ScriptTarget.ES2015,
 -       allowNonTsExtensions: true,
 -     })
 - 
 -     monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true)
 - 
 -     monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true)
 - 
 -     monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
 -       noSemanticValidation: true,
 -       noSyntaxValidation: true,
 -     })
 - 
 -     monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
 -       noSemanticValidation: true,
 -       noSyntaxValidation: true,
 -     })
 - 
 -     monaco.languages.typescript.javascriptDefaults.addExtraLib(codeAsString)
 - 
 -     monaco.languages.registerDocumentFormattingEditProvider("javascript", {
 -       async provideDocumentFormattingEdits(model) {
 -         const text = prettier.format(model.getValue(), {
 -           parser: "typescript",
 -           plugins: [parserTypeScript],
 -           singleQuote: true,
 -           trailingComma: "es5",
 -           semi: false,
 -         })
 - 
 -         return [
 -           {
 -             range: model.getFullModelRange(),
 -             text,
 -           },
 -         ]
 -       },
 -     })
 -   }, [])
 - 
 -   const handleMount = useCallback((editor: IMonacoEditor) => {
 -     if (editorRef) {
 -       editorRef.current = editor
 -     }
 -     rEditor.current = editor
 - 
 -     editor.updateOptions({
 -       fontSize,
 -       wordBasedSuggestions: false,
 -       minimap: { enabled: false },
 -       lightbulb: {
 -         enabled: false,
 -       },
 -       readOnly,
 -     })
 -   }, [])
 - 
 -   const handleChange = useCallback((code: string | undefined) => {
 -     onChange(code, rEditor.current)
 -   }, [])
 - 
 -   const handleKeydown = useCallback(
 -     (e: React.KeyboardEvent<HTMLDivElement>) => {
 -       onKey && onKey()
 -       e.stopPropagation()
 -       const metaKey = navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey
 -       if (e.key === "s" && metaKey) {
 -         const editor = rEditor.current
 -         if (!editor) return
 -         editor
 -           .getAction("editor.action.formatDocument")
 -           .run()
 -           .then(() =>
 -             onSave(rEditor.current?.getModel().getValue(), rEditor.current)
 -           )
 - 
 -         e.preventDefault()
 -       }
 -       if (e.key === "p" && metaKey) {
 -         e.preventDefault()
 -       }
 -       if (e.key === "d" && metaKey) {
 -         e.preventDefault()
 -       }
 -     },
 -     []
 -   )
 - 
 -   const handleKeyUp = useCallback(
 -     (e: React.KeyboardEvent<HTMLDivElement>) => e.stopPropagation(),
 -     []
 -   )
 - 
 -   const rDecorations = useRef<any>([])
 - 
 -   useEffect(() => {
 -     const monaco = rMonaco.current
 -     if (!monaco) return
 -     const editor = rEditor.current
 -     if (!editor) return
 - 
 -     if (!error) {
 -       rDecorations.current = editor.deltaDecorations(rDecorations.current, [])
 -       return
 -     }
 - 
 -     if (!error.line) return
 - 
 -     rDecorations.current = editor.deltaDecorations(rDecorations.current, [
 -       {
 -         range: new monaco.Range(
 -           Number(error.line) - 1,
 -           0,
 -           Number(error.line) - 1,
 -           0
 -         ),
 -         options: {
 -           isWholeLine: true,
 -           className: "editorLineError",
 -         },
 -       },
 -     ])
 -   }, [error])
 - 
 -   useEffect(() => {
 -     const monaco = rMonaco.current
 -     if (!monaco) return
 -     monaco.editor.setTheme(theme === "dark" ? "vs-dark" : "light")
 -   }, [theme])
 - 
 -   useEffect(() => {
 -     const editor = rEditor.current
 -     if (!editor) return
 - 
 -     editor.updateOptions({
 -       fontSize,
 -     })
 -   }, [fontSize])
 - 
 -   return (
 -     <EditorContainer onKeyDown={handleKeydown} onKeyUp={handleKeyUp}>
 -       <Editor
 -         height="100%"
 -         language="javascript"
 -         value={value}
 -         theme={theme === "dark" ? "vs-dark" : "light"}
 -         beforeMount={handleBeforeMount}
 -         onMount={handleMount}
 -         onChange={handleChange}
 -       />
 -     </EditorContainer>
 -   )
 - }
 - 
 - const EditorContainer = styled("div", {
 -   height: "100%",
 -   pointerEvents: "all",
 -   userSelect: "all",
 - 
 -   ".editorLineError": {
 -     backgroundColor: "$lineError",
 -   },
 - })
 
 
  |