Optimize CodeEditor. CodeEditor add tsconfig support.
This commit is contained in:
@@ -3,12 +3,13 @@ import { editor, Selection } from 'monaco-editor'
|
||||
import MonacoEditor, { Monaco } from '@monaco-editor/react'
|
||||
import '@/components/Playground/CodeEditor/Editor/editor.scss'
|
||||
import '@/components/Playground/CodeEditor/Editor/loader'
|
||||
import { IEditorOptions, IFiles, ITheme } from '@/components/Playground/shared'
|
||||
import { fileNameToLanguage } from '@/components/Playground/files'
|
||||
import { IEditorOptions, IFiles, ITheme, ITsConfig } from '@/components/Playground/shared'
|
||||
import { fileNameToLanguage, tsconfigJsonDiagnosticsOptions } from '@/components/Playground/files'
|
||||
import { useEditor, useTypesProgress } from '@/components/Playground/CodeEditor/Editor/hooks'
|
||||
import { MonacoEditorConfig } from '@/components/Playground/CodeEditor/Editor/monacoConfig'
|
||||
|
||||
interface EditorProps {
|
||||
tsConfig?: ITsConfig
|
||||
files?: IFiles
|
||||
selectedFileName?: string
|
||||
readonly?: boolean
|
||||
@@ -19,6 +20,7 @@ interface EditorProps {
|
||||
}
|
||||
|
||||
const Editor: React.FC<EditorProps> = ({
|
||||
tsConfig,
|
||||
files = {},
|
||||
selectedFileName = '',
|
||||
readonly,
|
||||
@@ -28,6 +30,7 @@ const Editor: React.FC<EditorProps> = ({
|
||||
onJumpFile
|
||||
}) => {
|
||||
const editorRef = useRef<editor.IStandaloneCodeEditor>()
|
||||
const monacoRef = useRef<Monaco>()
|
||||
const { doOpenEditor, loadJsxSyntaxHighlight, autoLoadExtraLib } = useEditor()
|
||||
const jsxSyntaxHighlightRef = useRef<{
|
||||
highlighter: (code?: string | undefined) => void
|
||||
@@ -39,16 +42,12 @@ const Editor: React.FC<EditorProps> = ({
|
||||
const { total, finished, onWatch } = useTypesProgress()
|
||||
const file = files[selectedFileName] || { name: 'Untitled' }
|
||||
|
||||
const handleOnEditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => {
|
||||
editorRef.current = editor
|
||||
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
|
||||
void editor.getAction('editor.action.formatDocument')?.run()
|
||||
})
|
||||
|
||||
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
|
||||
jsx: monaco.languages.typescript.JsxEmit.Preserve,
|
||||
esModuleInterop: true
|
||||
})
|
||||
const handleOnEditorWillMount = (monaco: Monaco) => {
|
||||
monaco.languages.json.jsonDefaults.setDiagnosticsOptions(tsconfigJsonDiagnosticsOptions)
|
||||
tsConfig &&
|
||||
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(
|
||||
tsConfig.compilerOptions
|
||||
)
|
||||
|
||||
files &&
|
||||
Object.entries(files).forEach(([key]) => {
|
||||
@@ -60,6 +59,15 @@ const Editor: React.FC<EditorProps> = ({
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleOnEditorDidMount = (editor: editor.IStandaloneCodeEditor, monaco: Monaco) => {
|
||||
editorRef.current = editor
|
||||
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
|
||||
void editor.getAction('editor.action.formatDocument')?.run()
|
||||
})
|
||||
|
||||
monacoRef.current = monaco
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
@@ -85,6 +93,13 @@ const Editor: React.FC<EditorProps> = ({
|
||||
jsxSyntaxHighlightRef?.current?.highlighter?.()
|
||||
}, [file.name])
|
||||
|
||||
useEffect(() => {
|
||||
tsConfig &&
|
||||
monacoRef.current?.languages.typescript.typescriptDefaults.setCompilerOptions(
|
||||
tsConfig.compilerOptions
|
||||
)
|
||||
}, [tsConfig])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div data-component={'playground-code-editor-editor'}>
|
||||
@@ -95,6 +110,7 @@ const Editor: React.FC<EditorProps> = ({
|
||||
language={file.language}
|
||||
value={file.value}
|
||||
onChange={onChange}
|
||||
beforeMount={handleOnEditorWillMount}
|
||||
onMount={handleOnEditorDidMount}
|
||||
options={{
|
||||
...MonacoEditorConfig,
|
||||
|
||||
@@ -85,6 +85,7 @@ const Item: React.FC<ItemProps> = ({
|
||||
setFileName(value)
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus()
|
||||
inputRef.current?.setSelectionRange(0, inputRef.current?.value.lastIndexOf('.'))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -119,6 +120,7 @@ const Item: React.FC<ItemProps> = ({
|
||||
onChange={handleOnChange}
|
||||
onBlur={finishNameFile}
|
||||
onKeyDown={handleKeyDown}
|
||||
spellCheck={'false'}
|
||||
/>
|
||||
<span className={'tab-item-input-mask'}>{fileName}</span>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,11 @@ import '@/components/Playground/CodeEditor/FileSelector/file-selector.scss'
|
||||
import HideScrollbar, { HideScrollbarElement } from '@/components/common/HideScrollbar'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import { IFiles } from '@/components/Playground/shared'
|
||||
import { getFileNameList, IMPORT_MAP_FILE_NAME } from '@/components/Playground/files'
|
||||
import {
|
||||
getFileNameList,
|
||||
IMPORT_MAP_FILE_NAME,
|
||||
TS_CONFIG_FILE_NAME
|
||||
} from '@/components/Playground/files'
|
||||
import Item from '@/components/Playground/CodeEditor/FileSelector/Item'
|
||||
|
||||
interface FileSelectorProps {
|
||||
@@ -85,6 +89,14 @@ const FileSelector: React.FC<FileSelectorProps> = ({
|
||||
onChange?.(IMPORT_MAP_FILE_NAME)
|
||||
}
|
||||
|
||||
const editTsConfig = () => {
|
||||
if (hasEditing) {
|
||||
return
|
||||
}
|
||||
|
||||
onChange?.(TS_CONFIG_FILE_NAME)
|
||||
}
|
||||
|
||||
const handleOnSaveTab = (value: string, item: string) => {
|
||||
if (creating) {
|
||||
onAddFile?.(value)
|
||||
@@ -122,7 +134,9 @@ const FileSelector: React.FC<FileSelectorProps> = ({
|
||||
onRemoveFile?.(fileName)
|
||||
if (fileName === selectedFileName) {
|
||||
const keys = getFileNameList(files).filter(
|
||||
(item) => ![IMPORT_MAP_FILE_NAME].includes(item) && !files[item].hidden
|
||||
(item) =>
|
||||
![IMPORT_MAP_FILE_NAME, TS_CONFIG_FILE_NAME].includes(item) &&
|
||||
!files[item].hidden
|
||||
)
|
||||
const index = keys.indexOf(fileName) - 1
|
||||
if (index >= 0) {
|
||||
@@ -137,7 +151,9 @@ const FileSelector: React.FC<FileSelectorProps> = ({
|
||||
getFileNameList(files).length
|
||||
? setTabs(
|
||||
getFileNameList(files).filter(
|
||||
(item) => ![IMPORT_MAP_FILE_NAME].includes(item) && !files[item].hidden
|
||||
(item) =>
|
||||
![IMPORT_MAP_FILE_NAME, TS_CONFIG_FILE_NAME].includes(item) &&
|
||||
!files[item].hidden
|
||||
)
|
||||
)
|
||||
: setTabs([])
|
||||
@@ -179,14 +195,24 @@ const FileSelector: React.FC<FileSelectorProps> = ({
|
||||
</FlexBox>
|
||||
</HideScrollbar>
|
||||
</div>
|
||||
{files[IMPORT_MAP_FILE_NAME] && (
|
||||
{(files[IMPORT_MAP_FILE_NAME] || files[TS_CONFIG_FILE_NAME]) && (
|
||||
<div className={'sticky'}>
|
||||
<Item
|
||||
value={'Import Map'}
|
||||
active={selectedFileName === IMPORT_MAP_FILE_NAME}
|
||||
onClick={editImportMap}
|
||||
readonly
|
||||
/>
|
||||
{files[TS_CONFIG_FILE_NAME] && (
|
||||
<Item
|
||||
value={'tsconfig.json'}
|
||||
active={selectedFileName === TS_CONFIG_FILE_NAME}
|
||||
onClick={editTsConfig}
|
||||
readonly
|
||||
/>
|
||||
)}
|
||||
{files[IMPORT_MAP_FILE_NAME] && (
|
||||
<Item
|
||||
value={'Import Map'}
|
||||
active={selectedFileName === IMPORT_MAP_FILE_NAME}
|
||||
onClick={editImportMap}
|
||||
readonly
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -2,17 +2,19 @@ import React from 'react'
|
||||
import _ from 'lodash'
|
||||
import '@/components/Playground/CodeEditor/code-editor.scss'
|
||||
import FlexBox from '@/components/common/FlexBox'
|
||||
import { IEditorOptions, IFiles, ITheme } from '@/components/Playground/shared'
|
||||
import { IEditorOptions, IFiles, ITheme, ITsConfig } from '@/components/Playground/shared'
|
||||
import {
|
||||
fileNameToLanguage,
|
||||
getFileNameList,
|
||||
IMPORT_MAP_FILE_NAME
|
||||
IMPORT_MAP_FILE_NAME,
|
||||
TS_CONFIG_FILE_NAME
|
||||
} from '@/components/Playground/files'
|
||||
import FileSelector from '@/components/Playground/CodeEditor/FileSelector'
|
||||
import Editor from '@/components/Playground/CodeEditor/Editor'
|
||||
|
||||
interface CodeEditorProps {
|
||||
theme?: ITheme
|
||||
tsConfig?: ITsConfig
|
||||
files: IFiles
|
||||
readonly?: boolean
|
||||
readonlyFiles?: string[]
|
||||
@@ -29,6 +31,7 @@ interface CodeEditorProps {
|
||||
|
||||
const CodeEditor: React.FC<CodeEditorProps> = ({
|
||||
theme,
|
||||
tsConfig,
|
||||
files,
|
||||
readonly,
|
||||
readonlyFiles,
|
||||
@@ -43,7 +46,7 @@ const CodeEditor: React.FC<CodeEditorProps> = ({
|
||||
...props
|
||||
}) => {
|
||||
const filteredFilesName = getFileNameList(files).filter(
|
||||
(item) => ![IMPORT_MAP_FILE_NAME].includes(item) && !files[item].hidden
|
||||
(item) => ![IMPORT_MAP_FILE_NAME, TS_CONFIG_FILE_NAME].includes(item) && !files[item].hidden
|
||||
)
|
||||
const propsSelectedFileName =
|
||||
props.selectedFileName || (filteredFilesName.length ? filteredFilesName[0] : '')
|
||||
@@ -101,7 +104,7 @@ const CodeEditor: React.FC<CodeEditorProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnChangeFileContent = _.debounce((code = '') => {
|
||||
const handleOnChangeFileContent = _.debounce((code: string = '') => {
|
||||
if (!files[onSelectedFileChange ? propsSelectedFileName : selectedFileName]) {
|
||||
return
|
||||
}
|
||||
@@ -131,6 +134,7 @@ const CodeEditor: React.FC<CodeEditorProps> = ({
|
||||
onError={handleOnError}
|
||||
/>
|
||||
<Editor
|
||||
tsConfig={tsConfig}
|
||||
theme={theme}
|
||||
selectedFileName={
|
||||
onSelectedFileChange ? propsSelectedFileName : selectedFileName
|
||||
|
||||
Reference in New Issue
Block a user