drone/web/src/components/SourceCodeEditor/MonacoSourceCodeEditor.tsx

103 lines
2.9 KiB
TypeScript

import React, { useEffect } from 'react'
import { Container } from '@harness/uicore'
import type monacoEditor from 'monaco-editor/esm/vs/editor/editor.api'
import MonacoEditor from 'react-monaco-editor'
import { noop } from 'lodash-es'
import { SourceCodeEditorProps, PLAIN_TEXT } from 'utils/Utils'
export const MonacoEditorOptions = {
ignoreTrimWhitespace: true,
minimap: { enabled: false },
codeLens: false,
scrollBeyondLastLine: false,
smartSelect: false,
tabSize: 2,
insertSpaces: true,
overviewRulerBorder: false,
automaticLayout: true
}
const diagnosticsOptions = {
noSemanticValidation: true,
noSyntaxValidation: true
}
const compilerOptions = {
jsx: 'react',
noLib: true,
allowNonTsExtensions: true
}
function autoAdjustEditorHeight(editor: monacoEditor.editor.IStandaloneCodeEditor) {
// Adjust editor height based on its content
// https://github.com/microsoft/monaco-editor/issues/794#issuecomment-427092969
const LINE_HEIGHT = 18
const CONTAINER_GUTTER = 10
const editorNode = editor.getDomNode() as HTMLElement
const codeContainer = editorNode.getElementsByClassName('view-lines')[0]
let prevLineCount = 0
const adjustHeight = () => {
const _height =
codeContainer.childElementCount > prevLineCount
? (codeContainer as HTMLElement).offsetHeight // unfold
: codeContainer.childElementCount * LINE_HEIGHT + CONTAINER_GUTTER // fold
prevLineCount = codeContainer.childElementCount
editorNode.style.height = Math.max(_height, 100) + 'px'
editor.layout()
}
setTimeout(adjustHeight, 0)
editor.onDidChangeModelDecorations(() => setTimeout(adjustHeight, 0))
}
const toOnOff = (flag: boolean) => (flag ? 'on' : 'off')
export default function MonacoSourceCodeEditor({
source,
language = PLAIN_TEXT,
lineNumbers = true,
readOnly = false,
className,
height,
autoHeight,
wordWrap = true,
onChange = noop
}: SourceCodeEditorProps) {
const scrollbar = autoHeight ? 'hidden' : 'auto'
useEffect(() => {
monaco.languages.typescript?.typescriptDefaults?.setDiagnosticsOptions?.(diagnosticsOptions)
monaco.languages.typescript?.javascriptDefaults?.setDiagnosticsOptions?.(diagnosticsOptions)
monaco.languages.typescript?.typescriptDefaults?.setCompilerOptions?.(compilerOptions)
}, [])
return (
<Container className={className}>
<MonacoEditor
language={language}
theme="vs-light"
value={source}
height={height}
options={{
...MonacoEditorOptions,
readOnly,
wordWrap: toOnOff(wordWrap),
lineNumbers: toOnOff(lineNumbers),
scrollbar: {
vertical: scrollbar,
horizontal: scrollbar,
alwaysConsumeMouseWheel: false
}
}}
editorDidMount={_editor => {
if (autoHeight) {
autoAdjustEditorHeight(_editor)
}
}}
onChange={onChange}
/>
</Container>
)
}