src/plugin/plugin-simple-bind-popup/index.tsx (235 lines of code) (raw):

import React, { Component } from 'react'; import { Button, Overlay } from '@alifd/next'; import { PluginProps } from '@alilc/lowcode-types'; import { event } from '@alilc/lowcode-engine'; import MonacoEditor from '@alilc/lowcode-plugin-base-monaco-editor'; import './index.less'; import { adjustOverlayPosition } from './utils'; const defaultEditorProps = { width: '100%', height: '150px', }; const defaultEditorOption = { options:{ readOnly: false, automaticLayout: true, folding: false, // 默认开启折叠代码功能 lineNumbers: 'off', wordWrap: 'on', formatOnPaste: true, fontSize: 12, tabSize: 2, scrollBeyondLastLine: false, fixedOverflowWidgets: false, snippetSuggestions: 'top', minimap: { enabled: false, }, scrollbar: { vertical: 'auto', horizontal: 'auto', verticalScrollbarSize:0 }, } }; export default class SimpleVariableBindPopup extends Component<PluginProps> { state = { visiable: false, isOverFlowMaxSize:false, jsCode: '', field: {}, // 编辑器全局变量 treeList: [], minimize: false, // 是否最小化 autoExpandParent: true, maxTextSize:0, // 绑定变量最大字符数 node: null as any as HTMLElement, // 触发的节点 }; private editorJsRef = React.createRef(); private nodeRef: HTMLDivElement | null = null; private overlayRef = React.createRef<HTMLDivElement>(); componentDidMount() { event.on('common:variableBindDialog.openDialog', ({ field, node, maxTextSize }) => { const finalMaxTextSize = maxTextSize && typeof maxTextSize === 'number' ? maxTextSize : this.props.config?.props?.maxTextSize; this.setState({ field, node: node || this.nodeRef, maxTextSize: finalMaxTextSize, }, () => { this.initCode(); this.openDialog(); }); }); } initCode = () => { const { field } = this.state; const fieldValue = field.getValue(); const jsCode = fieldValue?.value; this.setState({ jsCode, // fullScreenStatus: false, minimize: false, // 是否最小化 isOverFlowMaxSize:false, }); }; openDialog = () => { this.setState({ visiable: true }); }; closeDialog = () => { this.setState({ visiable: false, minimize: false, }); }; updateCode = (newCode) => { let isOverFlowMaxSize = false; if (this.state.maxTextSize){ isOverFlowMaxSize = newCode?.length > this.state.maxTextSize } this.setState( { jsCode: newCode, isOverFlowMaxSize }, this.autoSave, ); }; autoSave = () => { const { autoSave } = this.props; if (autoSave) { this.onOk(true); } }; editorDidMount = () => { setTimeout(() => { this.editorNode = this.editorJsRef.current; // 记录当前dom节点; }, 0); }; onOk = (autoSave) => { const { field, jsCode } = this.state; if(jsCode === undefined || jsCode?.length == 0) { return this.removeTheBinding() } const fieldValue = field.getValue(); field.setValue({ type: 'JSExpression', value: jsCode, mock: Object.prototype.toString.call(fieldValue) === '[object Object]' ? fieldValue.mock : fieldValue, }); if (autoSave !== true) { this.closeDialog(); } }; removeTheBinding = () => { const { field } = this.state; const fieldValue = field.getValue(); const value = Object.prototype.toString.call(fieldValue) === '[object Object]' ? fieldValue.mock : fieldValue; console.debug('value', value, 'fieldValue', fieldValue, field) field.setValue(value); this.closeDialog(); }; renderBottom = () => { const { jsCode } = this.state; return ( <div className="simple-bind-dialog-bottom"> <div className="bottom-left-container"> {jsCode && jsCode.length > 0 && ( <Button type="normal" warning onClick={this.removeTheBinding}> 移除绑定 </Button> )} </div> <div className="bottom-right-container"> <Button type="primary" onClick={this.onOk} disabled={this.isBtnDisable()}> 确定 </Button> &nbsp;&nbsp; <Button type="normal" onClick={this.closeDialog}> 取消 </Button> </div> </div> ); }; minimizeClick = (state) => { this.setState({ minimize: state, visiable: !state, }); }; renderErrorMessage = () => { const {isOverFlowMaxSize,maxTextSize} = this.state; return ( isOverFlowMaxSize ? <span className='error-message'>表达式文本不能超过{maxTextSize}个字符,请换成函数调用</span> :null ) } isBtnDisable = () => { const { isOverFlowMaxSize } = this.state; return isOverFlowMaxSize; } render() { const { visiable, jsCode, minimize, isOverFlowMaxSize, } = this.state; return ( <div> {minimize ? ( <div className="vs-variable-minimize"> <img onClick={() => this.minimizeClick(false)} src="https://img.alicdn.com/imgextra/i2/O1CN01HzeCND1vl948xPEWm_!!6000000006212-55-tps-200-200.svg" /> <span onClick={() => this.minimizeClick(false)} className="vs-variable-minimize-title"> 变量绑定 </span> <img onClick={this.closeDialog} src="https://img.alicdn.com/imgextra/i2/O1CN017cO64O1DzwlxwDSKW_!!6000000000288-55-tps-200-200.svg" /> </div> ) : ( '' )} <div style={{ position: 'absolute', top: 0, right: 100 }} ref={ref => this.nodeRef = ref} /> {this.state.node && <Overlay v2 key={this.state.field?.id} visible={!minimize && visiable} onRequestClose={this.closeDialog} safeNode={[document.querySelector('.lc-left-area'), document.querySelector('.lc-left-fixed-pane')]} target={() => this.state.node} offset={[-380, 0]} onPosition={() => { adjustOverlayPosition(this.overlayRef.current!, [20]) }} > <div className="simple-dialog-body" ref={this.overlayRef}> <div className="dialog-right-container"> <div className="dialog-small-title">绑定 {this.renderErrorMessage()}</div> <div id="jsEditorDom" className={isOverFlowMaxSize?"editor-context editor-context-error":"editor-context"} ref={this.editorJsRef}> <div className="editor-type-tag">=</div> <MonacoEditor value={jsCode} {...defaultEditorProps} {...defaultEditorOption} {...{ language: 'javascript' }} onChange={(newCode) => this.updateCode(newCode)} editorDidMount={(useMonaco, editor) => { this.editorDidMount.call(this, editor, useMonaco); }} /> </div> </div> {this.renderBottom()} </div> </Overlay> } </div> ); } }