add source-editor pannel

This commit is contained in:
zude.hzd 2020-04-19 22:13:58 +08:00
parent 2cf8573b78
commit d03844c706
13 changed files with 497 additions and 8 deletions

View File

@ -1,4 +1,6 @@
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
module.exports = ({ onGetWebpackConfig }) => {
onGetWebpackConfig((config) => {
@ -7,6 +9,16 @@ module.exports = ({ onGetWebpackConfig }) => {
.use(TsconfigPathsPlugin, [{
configFile: "./tsconfig.json"
}]);
config
// 定义插件名称
.plugin('MonacoWebpackPlugin')
// 第一项为具体插件,第二项为插件参数
.use(new MonacoWebpackPlugin({
languages:["javascript","css","json"]
}), []);
config.plugins.delete('hot');
config.devServer.hot(false);
});

View File

@ -18,6 +18,7 @@
"@ali/lowcode-plugin-event-bind-dialog": "^0.8.0",
"@ali/lowcode-plugin-outline-pane": "^0.8.7",
"@ali/lowcode-plugin-sample-logo": "^0.8.0",
"@ali/lowcode-plugin-source-editor":"^0.8.2",
"@ali/lowcode-plugin-sample-preview": "^0.8.6",
"@ali/lowcode-plugin-settings-pane": "^0.8.8",
"@ali/lowcode-plugin-undo-redo": "^0.8.0",
@ -41,6 +42,7 @@
"build-plugin-fusion": "^0.1.0",
"build-plugin-moment-locales": "^0.1.0",
"build-plugin-react-app": "^1.1.2",
"monaco-editor-webpack-plugin":"^1.9.0",
"tsconfig-paths-webpack-plugin": "^3.2.0"
}
}

View File

@ -83,17 +83,18 @@ module.exports = {
pluginProps: {
}
},
{
pluginKey: 'outlinePane',
pluginKey: 'soueceEditor',
type: 'PanelIcon',
props: {
align: 'top',
icon: 'shuxingkongjian',
title: '大纲树'
title: '源码面板'
},
config: {
package: '@ali/lowcode-plugin-outline-pane',
version: '^0.8.0'
package: '@ali/lowcode-plugin-source-editor',
version: '^0.8.2'
},
pluginProps: {}
},
@ -137,6 +138,7 @@ module.exports = {
version: '^0.8.0'
}
}
]
},
hooks: [],

View File

@ -8,6 +8,7 @@ import zhEn from '@ali/lowcode-plugin-zh-en';
import settingsPane from '@ali/lowcode-plugin-settings-pane';
import designer from '@ali/lowcode-plugin-designer';
import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog';
import sourceEditor from '@ali/lowcode-plugin-source-editor'
export default {
LowcodeSkeleton,
logo,
@ -18,5 +19,6 @@ export default {
zhEn,
settingsPane,
designer,
eventBindDialog
};
eventBindDialog,
sourceEditor
};

View File

@ -90,7 +90,30 @@ export default {
"version": "^0.8.0"
},
"pluginProps": {}
}, {
},
{
"pluginKey": "sourceEditor",
"type": "PanelIcon",
"props": {
"align": "top",
"icon": "zujianku",
"title": "组件库",
"panelProps":{
"floatable": true,
"defaultWidth":500
},
},
"config": {
"package": "@ali/lowcode-plugin-source-editor",
"version": "^0.8.0"
},
"pluginProps": {}
},
{
"pluginKey": "zhEn",
"type": "Custom",
"props": {
@ -124,7 +147,8 @@ export default {
"package": "@ali/lowcode-plugin-event-bind-dialog",
"version": "^0.8.0"
}
}]
},
]
},
"hooks": [],
"shortCuts": [],

View File

@ -0,0 +1,20 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
<a name="0.8.2"></a>
## [0.8.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-plugin-variable-bind-dialog@0.8.1...@ali/lowcode-plugin-variable-bind-dialog@0.8.2) (2020-03-30)
**Note:** Version bump only for package @ali/lowcode-plugin-source-editor
<a name="0.8.1"></a>
## 0.8.1 (2020-03-30)
**Note:** Version bump only for package @ali/lowcode-plugin-source-editor

View File

@ -0,0 +1 @@
## todo

View File

@ -0,0 +1,9 @@
{
"plugins": [
"build-plugin-component",
"build-plugin-fusion",
["build-plugin-moment-locales", {
"locales": ["zh-cn"]
}]
]
}

View File

@ -0,0 +1,41 @@
{
"name": "@ali/lowcode-plugin-source-editor",
"version": "0.8.2",
"description": "alibaba lowcode editor source-editor plugin",
"files": [
"es",
"lib"
],
"main": "lib/index.js",
"module": "es/index.js",
"scripts": {
"build": "build-scripts build --skip-demo",
"test": "ava",
"test:snapshot": "ava --update-snapshots"
},
"keywords": [
"lowcode",
"editor"
],
"author": "zude.hzd",
"dependencies": {
"@ali/lowcode-editor-core": "^0.8.0",
"@alifd/next": "^1.19.16",
"react": "^16.8.1",
"react-dom": "^16.8.1",
"prettier":"^1.18.2",
"js-beautify": "^1.10.1",
"react-monaco-editor": "^0.36.0"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.3",
"@types/react": "^16.9.13",
"@types/react-dom": "^16.9.4",
"build-plugin-component": "^0.2.7-1",
"build-plugin-fusion": "^0.1.0",
"build-plugin-moment-locales": "^0.1.0"
},
"publishConfig": {
"registry": "https://registry.npm.alibaba-inc.com"
}
}

View File

@ -0,0 +1,23 @@
.source-editor-container{
height: 100%;
.next-tabs {
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
height: 100%;
}
.next-tabs-content{
height: 100%;
}
.next-tabs-tabpane.active {
visibility: visible;
opacity: 1;
height: 100%;
}
}

View File

@ -0,0 +1,246 @@
import { Component, isValidElement, ReactElement, ReactNode } from 'react';
import { Tab, Search, Input, Button } from '@alifd/next';
import Editor from '@ali/lowcode-editor-core';
import { js_beautify, css_beautify } from 'js-beautify';
import MonacoEditor from 'react-monaco-editor';
// import lolizer from './sorceEditorPlugin',
import { Designer } from '@ali/lowcode-designer';
const TAB_KEY = {
JS_TAB: 'js_tab',
CSS_TAB: 'css_tab',
};
import './index.scss';
import transfrom from './transform';
const defaultEditorOption = {
width: '100%',
height: '96%',
options: {
readOnly: false,
automaticLayout: true,
folding: true, //默认开启折叠代码功能
lineNumbers: 'on',
wordWrap: 'off',
formatOnPaste: true,
fontSize: 12,
tabSize: 2,
scrollBeyondLastLine: false,
fixedOverflowWidgets: false,
snippetSuggestions: 'top',
minimap: {
enabled: false,
},
scrollbar: {
vertical: 'auto',
horizontal: 'auto',
},
}
};
export default class SourceEditor extends Component<{
editor: Editor;
}> {
private monocoEditer:Object;
private editorCmd:Object;
state = {
isShow: false,
tabKey: TAB_KEY.JS_TAB
}
componentWillMount() {
const { editor } = this.props;
editor.on('leftPanel.show', (key: String) => {
if (key === 'sourceEditor' && !this.monocoEditer) {
this.setState({
isShow: true,
});
}
});
// 添加函数
editor.on('sourceEditor.addFunction',(params:Object)=>{
this.callEditorEvent('sourceEditor.addFunction',params);
})
editor.once('designer.mount', (designer: Designer) => {
// let schema = designer.project.getSchema();
// mock data
let schema = {
componentTree: [
{
state: {
// 初始state 选填 对象类型/变量表达式
btnText: 'submit', // 默认数据值: 选填 变量表达式
},
css: 'body {font-size: 12px;} .botton{widht:100px;color:#ff00ff}', //css样式描述 选填
lifeCycles: {
//生命周期: 选填 对象类型
didMount: {
type: 'JSExpression',
value: "function() {\n \t\tconsole.log('did mount');\n\t}",
},
willUnmount: {
type: 'JSExpression',
value: "function() {\n \t\tconsole.log('will umount');\n\t}",
},
},
methods: {
//自定义方法对象: 选填 对象类型
testFunc: {
//自定义方法: 选填 函数类型
type: 'JSExpression',
value: "function() {\n \t\tconsole.log('testFunc');\n \t}",
},
},
},
],
};
this.initCode(schema);
});
setTimeout (()=>{
editor.emit('sourceEditor.addFunction',{
functionName:'testgaga'
})
},3000)
}
callEditorEvent = (eventName,params) => {
if (!this.monocoEditer){
this.editorCmd = {
eventName,
params
};
return;
}
if (eventName === 'sourceEditor.addFunction'){
this.addFunction(params);
}
}
initCode = (schema) => {
let jsCode = js_beautify(transfrom.schema2Code(schema),{ indent_size: 2, indent_empty_lines: true });
let css;
if (schema.componentTree[0].css) {
css = css_beautify(schema.componentTree[0].css,{ indent_size: 2 });
}
this.setState({
jsCode,
css,
selectTab: TAB_KEY.JS_TAB,
});
};
addFunction (params){
const count = this.monocoEditer.getModel().getLineCount() || 0;
const range = new monaco.Range(count, 1, count, 1);
const functionCode = transfrom.getNewFunctionCode(params.functionName);
this.monocoEditer.executeEdits('log-source', [{ identifier: 'event_id', range:range , text: functionCode, forceMoveMarkers:true }]);
this.updateCode(this.monocoEditer.getModel().getValue())
}
editorDidMount = (editor, monaco) => {
console.log('editorDidMount', editor);
this.monocoEditer = editor;
if (this.editorCmd){
this.callEditorEvent(this.editorCmd.eventName,this.editorCmd.params);
}
// var commandId = editor.addCommand(
// 0,
// function() {
// // services available in `ctx`
// alert('my command is executing!');
// },
// '',
// );
// monaco.languages.registerCodeLensProvider('javascript', {
// provideCodeLenses: function(model, token) {
// return {
// lenses: [
// {
// range: {
// startLineNumber: 1,
// startColumn: 1,
// endLineNumber: 1,
// endColumn: 1,
// },
// id: 'First Line',
// command: {
// id: commandId,
// title: 'First Line',
// },
// },
// ],
// };
// },
// resolveCodeLens: function(model, codeLens, token) {
// return codeLens;
// },
// });
};
onTabChange = (key) => {
this.setState({
selectTab: key,
});
};
updateCode = (newCode) => {
const { selectTab } = this.state;
if (selectTab === TAB_KEY.JS_TAB) {
this.setState({
jsCode: newCode,
});
} else {
this.setState({
css: newCode,
});
}
transfrom.code2Schema(newCode);
}
render() {
const { isShow, selectTab, jsCode, css } = this.state;
const tabs = [
{ tab: 'index.js', key: TAB_KEY.JS_TAB },
{ tab: 'style.css', key: TAB_KEY.CSS_TAB },
];
return (
<div className="source-editor-container">
<Tab size="small" shape="wrapped" onChange={this.onTabChange}>
{tabs.map((item) => (
<Tab.Item key={item.key} title={item.tab}>
{isShow && (
<MonacoEditor
value={selectTab == TAB_KEY.JS_TAB ? jsCode : css}
{...defaultEditorOption}
{...{ language: selectTab == TAB_KEY.JS_TAB ? 'javascript' : 'css' }}
onChange={(newCode) => this.updateCode(newCode)}
editorDidMount={this.editorDidMount}
/>
)}
</Tab.Item>
))}
</Tab>
</div>
);
}
}

View File

@ -0,0 +1,98 @@
import walkSourcePlugin from './sorceEditorPlugin';
const transfrom = {
schema2Code(schema: Object) {
let componentSchema = schema.componentTree[0];
let code =
`export default class {
${initStateCode(componentSchema)}
${initLifeCycleCode(componentSchema)}
${initMethodsCode(componentSchema)}
}`;
console.log(code);
return code;
},
code2Schema(code: String) {
let newCode = code.replace(/export default class/,'class A');
let A,a;
try {
A = eval('('+newCode + ')');
a = new A();
}catch(e){
return ''
}
let functionNameList = Object.getOwnPropertyNames(a.__proto__);
let functionMap = {};
functionNameList.map((functionName)=>{
if (functionName != 'constructor'){
let functionCode = a[functionName].toString().replace(new RegExp(functionName),'function');
functionMap[functionName] = functionCode;
}
})
console.log(JSON.stringify(a.state));
console.log(functionMap);
},
getNewFunctionCode(functionName:String){
return `\n\t${functionName}(){\n\t}\n`
}
};
function initStateCode(componentSchema:Object) {
if (componentSchema.state){
return `state = ${JSON.stringify(componentSchema.state)}`
}
return '';
}
function initLifeCycleCode(componentSchema: Object) {
if (componentSchema.lifeCycles) {
let lifeCycles = componentSchema.lifeCycles;
let codeList = [];
for (let key in lifeCycles) {
codeList.push(createFunctionCode(key, lifeCycles[key]));
}
return codeList.join('');
} else {
return '';
}
}
function initMethodsCode(componentSchema: Object) {
if (componentSchema.methods) {
let methods = componentSchema.methods;
let codeList = [];
for (let key in methods) {
codeList.push(createFunctionCode(key, methods[key]));
}
return codeList.join('');
} else {
return '';
}
}
function createFunctionCode(functionName: String, functionNode: Object) {
if (functionNode.type === 'JSExpression') {
let functionCode = functionNode.value;
functionCode = functionCode.replace(/function/, functionName);
return functionCode;
}
}
export default transfrom;

View File

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "lib"
},
"include": [
"./src/"
]
}