Optimize CodeEditor. CodeEditor add tsconfig support.

This commit is contained in:
2024-01-13 22:16:29 +08:00
parent 8e880cc1ed
commit 97c23334f7
11 changed files with 1043 additions and 65 deletions

View File

@@ -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,

View File

@@ -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>

View File

@@ -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>

View File

@@ -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