import React from 'react'; import {FormItem, FormControlProps, FormBaseControl} from './Item'; import LazyComponent from '../../components/LazyComponent'; import debouce from 'lodash/debounce'; import Editor from '../../components/Editor'; import {autobind} from '../../utils/helper'; import { isPureVariable, resolveVariableAndFilter } from '../../utils/tpl-builtin'; /** * Editor 代码编辑器 * 文档:https://baidu.gitee.io/amis/docs/components/form/editor */ export interface EditorControlSchema extends Omit { type: | 'editor' | 'bat-editor' | 'c-editor' | 'coffeescript-editor' | 'cpp-editor' | 'csharp-editor' | 'css-editor' | 'dockerfile-editor' | 'fsharp-editor' | 'go-editor' | 'handlebars-editor' | 'html-editor' | 'ini-editor' | 'java-editor' | 'javascript-editor' | 'json-editor' | 'less-editor' | 'lua-editor' | 'markdown-editor' | 'msdax-editor' | 'objective-c-editor' | 'php-editor' | 'plaintext-editor' | 'postiats-editor' | 'powershell-editor' | 'pug-editor' | 'python-editor' | 'r-editor' | 'razor-editor' | 'ruby-editor' | 'sb-editor' | 'scss-editor' | 'sol-editor' | 'sql-editor' | 'swift-editor' | 'typescript-editor' | 'vb-editor' | 'xml-editor' | 'yaml-editor'; /** * 语言类型 */ language?: | 'bat' | 'c' | 'coffeescript' | 'cpp' | 'csharp' | 'css' | 'dockerfile' | 'fsharp' | 'go' | 'handlebars' | 'html' | 'ini' | 'java' | 'javascript' | 'json' | 'less' | 'lua' | 'markdown' | 'msdax' | 'objective-c' | 'php' | 'plaintext' | 'postiats' | 'powershell' | 'pug' | 'python' | 'r' | 'razor' | 'ruby' | 'sb' | 'scss' | 'shell' | 'sol' | 'sql' | 'swift' | 'typescript' | 'vb' | 'xml' | 'yaml'; /** * 编辑器大小 */ size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; } export interface EditorProps extends FormControlProps { options?: object; } export default class EditorControl extends React.Component { static defaultProps: Partial = { language: 'javascript', editorTheme: 'vs', options: { automaticLayout: true, selectOnLineNumbers: true, scrollBeyondLastLine: false, folding: true, minimap: { enabled: false } } }; state = { focused: false }; editor: any; toDispose: Array = []; divRef = React.createRef(); constructor(props: EditorProps) { super(props); this.handleFocus = this.handleFocus.bind(this); this.handleBlur = this.handleBlur.bind(this); this.handleEditorMounted = this.handleEditorMounted.bind(this); } componentWillUnmount() { this.toDispose.forEach(fn => fn()); } handleFocus() { this.setState({ focused: true }); } handleBlur() { this.setState({ focused: false }); } handleEditorMounted(editor: any, monaco: any) { this.editor = editor; this.toDispose.push( editor.onDidChangeModelDecorations(() => { this.updateContainerSize(editor, monaco); // typing requestAnimationFrame( this.updateContainerSize.bind(this, editor, monaco) ); // folding }).dispose ); this.props.editorDidMount && this.props.editorDidMount(editor, monaco); } prevHeight = 0; @autobind updateContainerSize(editor: any, monaco: any) { if (!this.divRef.current) { return; } const lineHeight = editor.getOption(monaco.editor.EditorOption.lineHeight); const lineCount = editor.getModel()?.getLineCount() || 1; const height = editor.getTopForLineNumber(lineCount + 1) + lineHeight; if (this.prevHeight !== height) { this.prevHeight = height; this.divRef.current.style.height = `${height}px`; editor.layout(); } } render() { const { className, classPrefix: ns, classnames: cx, value, onChange, disabled, options, editorTheme, size, data } = this.props; let language = this.props.language; let finnalValue = value; if (finnalValue && typeof finnalValue !== 'string') { finnalValue = JSON.stringify(finnalValue, null, 2); } if (isPureVariable(language)) { language = resolveVariableAndFilter(language, data); } return (
); } } export const availableLanguages = [ 'bat', 'c', 'coffeescript', 'cpp', 'csharp', 'css', 'dockerfile', 'fsharp', 'go', 'handlebars', 'html', 'ini', 'java', 'javascript', 'json', 'less', 'lua', 'markdown', 'msdax', 'objective-c', 'php', 'plaintext', 'postiats', 'powershell', 'pug', 'python', 'r', 'razor', 'ruby', 'sb', 'scss', 'sol', 'shell', 'sql', 'swift', 'typescript', 'vb', 'xml', 'yaml' ]; export const EditorControls: Array< typeof EditorControl > = availableLanguages.map((lang: string) => { @FormItem({ type: `${lang}-editor`, sizeMutable: false }) class EditorControlRenderer extends EditorControl { static lang = lang; static displayName = `${lang[0].toUpperCase()}${lang.substring( 1 )}EditorControlRenderer`; static defaultProps = { ...EditorControl.defaultProps, language: lang }; } return EditorControlRenderer; }); @FormItem({ type: 'js-editor', sizeMutable: false }) class JavascriptEditorControlRenderer extends EditorControl { static defaultProps = { ...EditorControl.defaultProps, language: 'javascript' }; } @FormItem({ type: 'ts-editor', sizeMutable: false }) class TypescriptEditorControlRenderer extends EditorControl { static defaultProps = { ...EditorControl.defaultProps, language: 'typescript' }; } @FormItem({ type: `editor`, sizeMutable: false }) export class EditorControlRenderer extends EditorControl { static defaultProps = { ...EditorControl.defaultProps, language: 'javascript' }; }