diff --git a/packages/demo/build.plugin.js b/packages/demo/build.plugin.js
index 0fbf67f53..50ac34ddd 100644
--- a/packages/demo/build.plugin.js
+++ b/packages/demo/build.plugin.js
@@ -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);
});
diff --git a/packages/demo/package.json b/packages/demo/package.json
index 22110319c..fa20554b7 100644
--- a/packages/demo/package.json
+++ b/packages/demo/package.json
@@ -11,18 +11,19 @@
},
"config": {},
"dependencies": {
- "@ali/lowcode-editor-core": "^0.8.6",
- "@ali/lowcode-editor-skeleton": "^0.8.7",
- "@ali/lowcode-plugin-components-pane": "^0.8.5",
- "@ali/lowcode-plugin-designer": "^0.9.3",
- "@ali/lowcode-plugin-event-bind-dialog": "^0.8.6",
- "@ali/lowcode-plugin-outline-pane": "^0.8.9",
- "@ali/lowcode-plugin-sample-logo": "^0.8.5",
- "@ali/lowcode-plugin-sample-preview": "^0.8.8",
- "@ali/lowcode-plugin-settings-pane": "^0.8.10",
- "@ali/lowcode-plugin-undo-redo": "^0.8.6",
- "@ali/lowcode-plugin-variable-bind-dialog": "^0.8.4",
- "@ali/lowcode-plugin-zh-en": "^0.8.8",
+ "@ali/lowcode-editor-core": "^0.8.4",
+ "@ali/lowcode-editor-skeleton": "^0.8.0",
+ "@ali/lowcode-plugin-components-pane": "^0.8.0",
+ "@ali/lowcode-plugin-designer": "^0.9.1",
+ "@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",
+ "@ali/lowcode-plugin-variable-bind-dialog": "^0.8.2",
+ "@ali/lowcode-plugin-zh-en": "^0.8.6",
"@ali/lowcode-react-renderer": "^0.8.4",
"@ali/lowcode-runtime": "^0.8.10",
"@ali/lowcode-setters": "^0.8.8",
@@ -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"
}
}
diff --git a/packages/demo/skeleton.config.js b/packages/demo/skeleton.config.js
index 4dd4cc1c0..b649fd023 100644
--- a/packages/demo/skeleton.config.js
+++ b/packages/demo/skeleton.config.js
@@ -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: [],
diff --git a/packages/demo/src/editor/config/components.js b/packages/demo/src/editor/config/components.js
index 9648a7faf..348e048b7 100644
--- a/packages/demo/src/editor/config/components.js
+++ b/packages/demo/src/editor/config/components.js
@@ -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
-};
\ No newline at end of file
+ eventBindDialog,
+ sourceEditor
+};
diff --git a/packages/demo/src/editor/config/skeleton.js b/packages/demo/src/editor/config/skeleton.js
index a772f94ee..65d182436 100644
--- a/packages/demo/src/editor/config/skeleton.js
+++ b/packages/demo/src/editor/config/skeleton.js
@@ -68,7 +68,9 @@ export default {
"align": "top",
"icon": "zujianku",
"title": "组件库",
- "floatable": true
+ "panelProps": {
+ "floatable": true
+ }
},
"config": {
"package": "@ali/lowcode-plugin-components-pane",
@@ -88,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": {
@@ -122,7 +147,8 @@ export default {
"package": "@ali/lowcode-plugin-event-bind-dialog",
"version": "^0.8.0"
}
- }]
+ },
+ ]
},
"hooks": [],
"shortCuts": [],
diff --git a/packages/editor-core/src/index.ts b/packages/editor-core/src/index.ts
index 92e36fa4b..89ecdbfda 100644
--- a/packages/editor-core/src/index.ts
+++ b/packages/editor-core/src/index.ts
@@ -1,7 +1,6 @@
import Editor from './editor';
import * as utils from './utils';
-export * from './definitions';
export { default as PluginFactory } from './pluginFactory';
export { default as EditorContext } from './context';
diff --git a/packages/editor-skeleton/src/index.ts b/packages/editor-skeleton/src/index.ts
index c519f0552..061621d42 100644
--- a/packages/editor-skeleton/src/index.ts
+++ b/packages/editor-skeleton/src/index.ts
@@ -1,7 +1,9 @@
import Skeleton from './skeleton';
import Panel from './components/Panel';
import TopIcon from './components/TopIcon';
+import TopPlugin from './components/TopPlugin';
+import LeftPlugin from './components/LeftPlugin';
export default Skeleton;
-export { Panel, TopIcon };
+export { Panel, TopIcon, TopPlugin, LeftPlugin };
diff --git a/packages/plugin-source-editor/CHANGELOG.md b/packages/plugin-source-editor/CHANGELOG.md
new file mode 100644
index 000000000..7c5e8d83c
--- /dev/null
+++ b/packages/plugin-source-editor/CHANGELOG.md
@@ -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.
+
+
+## [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
+
+
+## 0.8.1 (2020-03-30)
+
+
+
+
+**Note:** Version bump only for package @ali/lowcode-plugin-source-editor
diff --git a/packages/plugin-source-editor/README.md b/packages/plugin-source-editor/README.md
new file mode 100644
index 000000000..8a6fb13f0
--- /dev/null
+++ b/packages/plugin-source-editor/README.md
@@ -0,0 +1 @@
+## todo
diff --git a/packages/plugin-source-editor/build.json b/packages/plugin-source-editor/build.json
new file mode 100644
index 000000000..e791d5b6b
--- /dev/null
+++ b/packages/plugin-source-editor/build.json
@@ -0,0 +1,9 @@
+{
+ "plugins": [
+ "build-plugin-component",
+ "build-plugin-fusion",
+ ["build-plugin-moment-locales", {
+ "locales": ["zh-cn"]
+ }]
+ ]
+}
diff --git a/packages/plugin-source-editor/package.json b/packages/plugin-source-editor/package.json
new file mode 100644
index 000000000..19c1c9178
--- /dev/null
+++ b/packages/plugin-source-editor/package.json
@@ -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"
+ }
+}
diff --git a/packages/plugin-source-editor/src/index.scss b/packages/plugin-source-editor/src/index.scss
new file mode 100644
index 000000000..02b902227
--- /dev/null
+++ b/packages/plugin-source-editor/src/index.scss
@@ -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%;
+ }
+
+}
+
diff --git a/packages/plugin-source-editor/src/index.tsx b/packages/plugin-source-editor/src/index.tsx
new file mode 100644
index 000000000..f1dba0d4e
--- /dev/null
+++ b/packages/plugin-source-editor/src/index.tsx
@@ -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 (
+
+
+ {tabs.map((item) => (
+
+ {isShow && (
+ this.updateCode(newCode)}
+ editorDidMount={this.editorDidMount}
+ />
+ )}
+
+ ))}
+
+
+ );
+ }
+}
diff --git a/packages/plugin-source-editor/src/transform.ts b/packages/plugin-source-editor/src/transform.ts
new file mode 100644
index 000000000..35a87934a
--- /dev/null
+++ b/packages/plugin-source-editor/src/transform.ts
@@ -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;
diff --git a/packages/plugin-source-editor/tsconfig.json b/packages/plugin-source-editor/tsconfig.json
new file mode 100644
index 000000000..c37b76ecc
--- /dev/null
+++ b/packages/plugin-source-editor/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "lib"
+ },
+ "include": [
+ "./src/"
+ ]
+}
diff --git a/packages/react-renderer/src/adapter/rax.jsx b/packages/react-renderer/src/adapter/rax.jsx
deleted file mode 100644
index 85176ff68..000000000
--- a/packages/react-renderer/src/adapter/rax.jsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { createElement, render, useState } from 'rax';
-import React, { PureComponent } from 'react';
-import DriverUniversal from 'driver-universal';
-import { Engine } from '@ali/iceluna-rax';
-import findDOMNode from 'rax-find-dom-node';
-
-let updateRax = () => {};
-
-export default class Rax extends PureComponent {
- constructor(props) {
- super(props);
- }
-
- componentDidMount() {
- const RaxEngine = () => {
- const [config, setConfig] = useState(this.props);
- updateRax = setConfig;
- return createElement(Engine, {
- ...config,
- });
- };
- render(createElement(RaxEngine), document.getElementById('luna-rax-container'), { driver: DriverUniversal });
- }
- componentDidUpdate() {
- updateRax(this.props);
- }
-
- render() {
- return ;
- }
-}
-
-Rax.findDOMNode = findDOMNode;
diff --git a/packages/react-renderer/src/comp/addon/index.jsx b/packages/react-renderer/src/comp/addon/index.jsx
deleted file mode 100644
index 1222a8c8b..000000000
--- a/packages/react-renderer/src/comp/addon/index.jsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-
-import AppContext from '../../context/appContext';
-import { isEmpty, generateI18n, goldlog } from '../../utils';
-
-export default class Addon extends PureComponent {
- static displayName = 'lunaAddon';
- static propTypes = {
- config: PropTypes.object,
- locale: PropTypes.string,
- messages: PropTypes.object,
- };
- static defaultProps = {
- config: {},
- };
- static contextType = AppContext;
- constructor(props, context) {
- super(props, context);
- if (isEmpty(props.config) || !props.config.addonKey) {
- console.warn('luna addon has wrong config');
- return;
- }
- // 插件上下文中的appHelper使用IDE的appHelper
- context.appHelper = (window.__ctx && window.__ctx.appHelper) || context.appHelper;
- context.locale = props.locale;
- context.messages = props.messages;
- // 注册插件
- this.appHelper = context.appHelper;
- let { locale, messages } = props;
- this.i18n = generateI18n(locale, messages);
- this.addonKey = props.config.addonKey;
- this.appHelper.addons = this.appHelper.addons || {};
- this.appHelper.addons[this.addonKey] = this;
- }
-
- async componentWillUnmount() {
- // 销毁插件
- const config = this.props.config || {};
- if (config && this.appHelper.addons) {
- delete this.appHelper.addons[config.addonKey];
- }
- }
-
- open = () => {
- return true;
- };
-
- close = () => {
- return true;
- };
-
- goldlog = (goKey, params) => {
- const { addonKey, addonConfig = {} } = this.props.config || {};
- goldlog(
- goKey,
- {
- addonKey,
- package: addonConfig.package,
- version: addonConfig.version,
- ...this.appHelper.logParams,
- ...params,
- },
- 'addon',
- );
- };
-
- get utils() {
- return this.appHelper.utils;
- }
-
- get constants() {
- return this.appHelper.constants;
- }
-
- get history() {
- return this.appHelper.history;
- }
-
- get location() {
- return this.appHelper.location;
- }
-
- render() {
- return null;
- }
-}
diff --git a/packages/react-renderer/src/comp/canvas/index.jsx b/packages/react-renderer/src/comp/canvas/index.jsx
deleted file mode 100644
index 355eba566..000000000
--- a/packages/react-renderer/src/comp/canvas/index.jsx
+++ /dev/null
@@ -1,729 +0,0 @@
-import React, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import { on, off } from '@ali/b3-one/lib/event';
-import AppHelper from '../../utils/appHelper';
-import SchemaHelper from '../../utils/schemaHelper';
-import DndHelper from '../../utils/dndHelper';
-import Engine from '../../engine';
-
-import CompFactory from '../../hoc/compFactory';
-import {
- isSchema,
- isFileSchema,
- isEmpty,
- isJSSlot,
- jsonuri,
- registShortCuts,
- unRegistShortCuts,
- generateUtils,
- parseObj,
- shallowEqual,
- addCssTag,
- transformSchemaToPure,
- goldlog,
-} from '../../utils';
-import './index.scss';
-
-const DESIGN_MODE = {
- EXTEND: 'extend',
- BORDER: 'border',
- PREVIEW: 'preview',
-};
-
-const DEFAULT_PLACEHOLDER = {
- emptyImage: '//img.alicdn.com/tfs/TB1zpkUoUT1gK0jSZFhXXaAtVXa-620-430.png',
- emptyText: '当前页面为空~\n请拖拽组件放入页面容器内吧!',
- nullImage: '//img.alicdn.com/tfs/TB1m_oSoND1gK0jSZFsXXbldVXa-620-430.png',
- nullText: '编辑内容不存在~!',
-};
-
-export default class Canvas extends PureComponent {
- static displayName = 'Canvas';
- static propTypes = {
- appHelper: PropTypes.object,
- components: PropTypes.object,
- engine: PropTypes.element,
- onCreate: PropTypes.func,
- initSchema: PropTypes.object,
- shortCuts: PropTypes.array,
- utils: PropTypes.object,
- };
- static defaultProps = {
- components: {},
- engine: Engine,
- onCreate: () => {},
- initSchema: {},
- shortCuts: [],
- utils: {},
- };
- constructor(props) {
- super(props);
- this.appHelper = props.appHelper || new AppHelper();
- if (!this.appHelper.schemaHelper) {
- this.appHelper.set('schemaHelper', new SchemaHelper(props.initSchema || {}, this.appHelper));
- }
- this.appHelper.set('basicSchemaHelper', this.appHelper.schemaHelper);
- if (!this.appHelper.dndHelper) {
- this.appHelper.set('dndHelper', new DndHelper(this.appHelper));
- }
- this.appHelper.dndHelper.setCanvasWin(window);
- if (this.appHelper.designMode === undefined) {
- this.appHelper.designMode = 'extend';
- }
-
- this.canvasAppHelper = new AppHelper({
- history: this.appHelper.history,
- location: this.appHelper.location,
- match: this.appHelper.match,
- });
-
- this.updateCanvasAppHelper(props);
- this.appHelper.once('ide.ready', () => {
- this.updateCanvasAppHelper(props);
- });
-
- window.__ctx = {
- appHelper: this.appHelper,
- canvasAppHelper: this.canvasAppHelper,
- components: this.props.components,
- };
-
- window.goldlog = window.goldlog || window.parent.goldlog;
-
- this.state = {
- canvasStack: [
- {
- lunaKey: 'root',
- lunaPath: '',
- name: 'root',
- schemaHelper: this.appHelper.schemaHelper,
- schema: this.appHelper.schemaHelper.get('schema'),
- },
- ],
- };
- this.appHelper.set('canvasStack', this.state.canvasStack);
- }
-
- componentDidMount() {
- const appHelper = this.appHelper;
- appHelper.batchOn(['behavior.undo', 'behavior.redo'], this.handleUndoRedo);
- appHelper.on('schema.reset', this.handleSchemaReset);
- appHelper.on('material.move', this.handleMaterialMove);
- appHelper.on('material.add', this.handleMaterialAdd);
- appHelper.on('material.remove', this.handleMaterialRemove);
- appHelper.on('material.up', this.handleMaterialMoveUp);
- appHelper.on('material.down', this.handleMaterialMoveDown);
- appHelper.on('material.copy', this.handleMaterialCopy);
- appHelper.on('material.update', this.handleMaterialUpdate);
- appHelper.on('material.select', this.handleMaterialSelect);
- appHelper.on('schemaHelper.schema.afterUpdate', this.handleReset);
- appHelper.on('designMode.change', this.handleDesignModeChange);
- appHelper.on('preview.change', this.handlePreviewChange);
- appHelper.on('canvas.stack.push', this.handleCanvasPush);
- appHelper.on('canvas.stack.pop', this.handleCanvasPop);
- appHelper.on('canvas.stack.jump', this.handleCanvasJump);
- appHelper.on('style.update', this.updateStyle);
- appHelper.batchOn(['utils.update', 'constants.update', 'componentsMap.update'], this.handleCanvasAppHelperUpdate);
- appHelper.on('viewPort.update', this.handleForceUpdate);
-
- registShortCuts(this.props.shortCuts, this.appHelper);
- this.appHelper.set('canvas', this);
- this.props.onCreate(this.appHelper);
- appHelper.emit('canvas.ready', this);
- goldlog(
- 'EXP',
- {
- action: 'appear',
- },
- 'canvas',
- );
- }
-
- componentWillUnmount() {
- const appHelper = this.appHelper;
- appHelper.batchOff(['behavior.undo', 'behavior.redo'], this.handleUndoRedo);
- appHelper.on('schema.reset', this.handleSchemaReset);
- appHelper.off('material.move', this.handleMaterialMove);
- appHelper.off('material.add', this.handleMaterialAdd);
- appHelper.off('material.remove', this.handleMaterialRemove);
- appHelper.off('material.up', this.handleMaterialMoveUp);
- appHelper.off('material.down', this.handleMaterialMoveDown);
- appHelper.off('material.copy', this.handleMaterialCopy);
- appHelper.off('material.update', this.handleMaterialUpdate);
- appHelper.off('material.select', this.handleMaterialSelect);
- appHelper.off('schemaHelper.schema.afterUpdate', this.handleReset);
- appHelper.off('designMode.change', this.handleDesignModeChange);
- appHelper.off('preview.change', this.handlePreviewChange);
- appHelper.off('canvas.stack.push', this.handleCanvasPush);
- appHelper.off('canvas.stack.pop', this.handleCanvasPop);
- appHelper.off('canvas.stack.jump', this.handleCanvasJump);
- appHelper.off('style.update', this.updateStyle);
- appHelper.batchOff(['utils.update', 'constants.update', 'componentsMap.update'], this.handleCanvasAppHelperUpdate);
- appHelper.off('viewPort.update', this.handleForceUpdate);
- unRegistShortCuts(this.props.shortCuts);
- }
-
- // 消息处理
-
- handleMaterialMove = ({ lunaKey, targetKey, direction }) => {
- const appHelper = this.appHelper;
- appHelper.schemaHelper.move(lunaKey, targetKey, direction);
- appHelper.emit('behavior.record');
- };
-
- handleMaterialAdd = ({ schema, targetKey, direction }) => {
- if (!isSchema(schema)) {
- throw new Error('物料schema结构异常,无法添加!');
- }
- const appHelper = this.appHelper;
- const addSchema = Array.isArray(schema) ? schema[0] : schema;
- // 对于没有设置文件名的容器组件,交给画布外层处理
- if (isFileSchema(addSchema) && !addSchema.fileName) {
- return appHelper.emit('onFileNameMaterial.add', { schema: addSchema, targetKey, direction });
- }
-
- const addKey = appHelper.schemaHelper.add(schema, targetKey, direction);
- appHelper.emit('behavior.record');
- this.autoSelectComponent(addKey);
- };
-
- handleMaterialRemove = (lunaKey) => {
- const appHelper = this.appHelper;
- const schemaHelper = appHelper.schemaHelper;
- const currCompSchema = schemaHelper.schemaMap[lunaKey];
- // 获取当前删除物料的相邻物料
- const nextCompSchema = jsonuri.get(
- schemaHelper.schema,
- currCompSchema.__ctx.lunaPath.replace(/\/(\d+)$/, (res, idx) => `/${parseInt(idx) + 1}`),
- );
- const activeKey = (nextCompSchema && nextCompSchema.__ctx.lunaKey) || currCompSchema.__ctx.parentKey;
- appHelper.schemaHelper.remove(lunaKey);
- appHelper.emit('behavior.record');
- this.autoSelectComponent(activeKey);
- };
-
- handleMaterialMoveUp = (lunaKey) => {
- const appHelper = this.appHelper;
- appHelper.schemaHelper && appHelper.schemaHelper.slide(lunaKey, 'up');
- appHelper.emit('behavior.record');
- };
-
- handleMaterialMoveDown = (lunaKey) => {
- const appHelper = this.appHelper;
- appHelper.schemaHelper && appHelper.schemaHelper.slide(lunaKey, 'down');
- appHelper.emit('behavior.record');
- };
-
- handleMaterialCopy = (lunaKey) => {
- const appHelper = this.appHelper;
- const addKey = appHelper.schemaHelper.copy(lunaKey);
-
- appHelper.emit('behavior.record');
- this.autoSelectComponent(addKey);
- };
-
- handleMaterialUpdate = ({ lunaKey, props, propsKey }) => {
- const appHelper = this.appHelper;
- appHelper.schemaHelper.update(lunaKey, props);
- appHelper.emit('behavior.record', { lunaKey, propsKey });
- };
-
- handleMaterialSelect = (lunaKey, options) => {
- const appHelper = this.appHelper;
- if (appHelper.activeKey === lunaKey) return;
- appHelper.set('activeKey', lunaKey);
- appHelper.emit('material.select.change', lunaKey, options);
- const preNode = document.querySelectorAll('[data-active=true]');
- if (preNode[0] && preNode[0].dataset.lunaKey === lunaKey) return;
- (preNode || []).forEach((item) => {
- item.removeAttribute('data-active');
- item.removeAttribute('data-nochild');
- });
- //判断是否容器组件且没有子元素
- if (!lunaKey) {
- window.parent.t = window.t = null;
- return;
- }
- let schema = appHelper.schemaHelper.schemaMap[lunaKey];
- if (!schema) return;
- let componentInfo = appHelper.componentsMap[schema.componentName];
- const currentNode = document.querySelectorAll(`[data-luna-key=${lunaKey}]`);
- (currentNode || []).forEach((item) => {
- item.setAttribute('data-active', 'true');
- if (componentInfo && componentInfo.isContainer && schema && (!schema.children || !schema.children.length)) {
- item.setAttribute('data-nochild', 'true');
- }
- });
- // for debug
- let ctx = this.appHelper.schemaHelper.compCtxMap[lunaKey];
- let ref = this.appHelper.schemaHelper.compThisMap[lunaKey];
- let t = {
- ctx,
- schema,
- ref,
- };
- t.__proto__ = ctx;
- window.parent.t = window.t = t;
- };
-
- handleDesignModeChange = (designMode) => {
- this.appHelper.set('designMode', designMode);
- this.forceUpdate();
- };
-
- handlePreviewChange = (isPreview) => {
- this.appHelper.set('isPreview', isPreview);
- this.forceUpdate();
- };
-
- handleUndoRedo = (schema) => {
- this.appHelper.schemaHelper.reset(schema);
- this.autoSelectComponent();
- };
-
- handleSchemaReset = (schema) => {
- this.appHelper.schemaHelper.reset(schema);
- this.appHelper.emit('behavior.record');
- this.autoSelectComponent();
- };
-
- handleReset = () => {
- this.updateCanvasStack();
- this.forceUpdate();
- this.updateStyle();
- };
-
- handleCanvasAppHelperUpdate = () => {
- this.updateCanvasAppHelper();
- this.forceUpdate();
- };
-
- handleForceUpdate = () => {
- this.forceUpdate();
- };
-
- handleCanvasPush = ({ schema, lunaKey, name }) => {
- const appHelper = this.appHelper;
- appHelper.emit('canvas.stack.beforePush');
- const { canvasStack } = this.state;
- const tempSchema = {
- componentName: 'Temp',
- fileName: 'temp',
- props: {},
- children: isJSSlot(schema) ? schema.value : schema, //兼容slot
- };
- const schemaHelper = new SchemaHelper(transformSchemaToPure(tempSchema), this.appHelper);
- const schemaMap = this.appHelper.schemaHelper.schemaMap || {};
- const compCtxMap = this.appHelper.schemaHelper.compCtxMap || {};
- const currentComp = schemaMap[lunaKey];
- const undoRedoKey = `${lunaKey}_${canvasStack.length}`;
- //若是第一层下钻需要先给最上层加上从appHelper中获取的undoRedoKey
- if (canvasStack.length === 1) {
- canvasStack[0].undoRedoKey = this.appHelper.undoRedoKey;
- }
- const currentData = {
- lunaKey,
- lunaPath: currentComp.__ctx.lunaPath,
- name,
- schema,
- schemaHelper,
- ctx: compCtxMap[lunaKey],
- undoRedoKey,
- componentName: currentComp.componentName,
- };
- appHelper.set('schemaHelper', schemaHelper);
- appHelper.undoRedoHelper && appHelper.undoRedoHelper.create(undoRedoKey, tempSchema);
- appHelper.set('undoRedoKey', undoRedoKey);
- appHelper.set('activeKey', null);
- this.setState(
- {
- canvasStack: [...this.state.canvasStack, currentData],
- },
- () => {
- this.appHelper.set('canvasStack', this.state.canvasStack);
- this.appHelper.emit('canvas.stack.afterPush', currentData, this.state.canvasStack);
- this.autoSelectComponent();
- },
- );
- };
-
- handleCanvasPop = () => {
- const { canvasStack } = this.state;
- if (canvasStack.length > 1) {
- this.handleCanvasJump(null, true);
- }
- };
-
- handleCanvasJump = (idx, isPop) => {
- const { canvasStack } = this.state;
- const appHelper = this.appHelper;
- let preIdx = idx + 1;
- if (isPop) {
- appHelper.emit('canvas.stack.beforePop');
- preIdx = canvasStack.length - 1;
- idx = preIdx - 1;
- } else {
- appHelper.emit('canvas.stack.beforeJump');
- }
- if (idx < 0 || idx > canvasStack.length - 1) return;
- const preData = canvasStack[preIdx];
- const currentData = canvasStack[idx];
- appHelper.set('schemaHelper', currentData.schemaHelper);
- appHelper.set('undoRedoKey', currentData.undoRedoKey);
- appHelper.undoRedoHelper && appHelper.undoRedoHelper.delete(preData.undoRedoKey);
- this.setState(
- {
- canvasStack: canvasStack.slice(0, idx + 1),
- },
- () => {
- appHelper.set('canvasStack', this.state.canvasStack);
- appHelper.schemaHelper.reset(appHelper.schemaHelper.schema);
- appHelper.emit('behavior.record');
- appHelper.emit(`canvas.stack.${isPop ? 'afterPop' : 'afterJump'}`, preData, this.state.canvasStack);
- this.autoSelectComponent(preData.lunaKey);
- },
- );
- };
-
- // 引擎处理函数
-
- handleCompGetCtx = (schema, ctx) => {
- const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey;
- if (!lunaKey) return;
- // console.log('+++++ getCtx', lunaKey, ctx);
- this.appHelper.schemaHelper.compCtxMap[lunaKey] = ctx;
- // for debug
- if (this.appHelper.activeKey && lunaKey === this.appHelper.activeKey) {
- let ref = this.appHelper.schemaHelper.compThisMap[lunaKey];
- let t = {
- ctx,
- schema,
- ref,
- };
- t.__proto__ = ctx;
- window.parent.t = window.t = t;
- }
- };
-
- handleCompGetRef = (schema, ref, topLevel) => {
- const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey;
- if (!lunaKey) return;
- // console.log('----- getRef', lunaKey, ref);
- const schemaHelper = this.appHelper.schemaHelper;
- schemaHelper.compThisMap[lunaKey] = ref;
- if (ref && !ref.__design) {
- this.updateDesignMode(ref, schema, topLevel);
- const didUpdate = ref.componentDidUpdate;
- ref.componentDidUpdate = (...args) => {
- didUpdate && didUpdate.apply(ref, args);
- this.updateDesignMode(ref, schema, topLevel);
- };
- const willUnmount = ref.componentWillUnmount;
- ref.componentWillUnmount = (...args) => {
- willUnmount && willUnmount.apply(ref, args);
- // console.log('----- destroy', lunaKey, ref);
- delete schemaHelper.compThisMap[lunaKey];
- delete schemaHelper.compCtxMap[lunaKey];
- };
- ref.__design = true;
- }
- };
-
- handleDnd = (type, ev, schema) => {
- const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey;
- const designMode = this.appHelper.designMode;
- if (!lunaKey || ![DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(designMode)) return;
- const dndHelper = this.appHelper && this.appHelper.dndHelper;
- if (dndHelper) {
- dndHelper[`handle${type}`](ev, lunaKey);
- }
- };
-
- //自动选中组件
- autoSelectComponent = (lunaKey) => {
- const appHelper = this.appHelper;
- // 若未指定需要选中的组件,且当前有选中的组件不做处理
- if (appHelper.activeKey && !lunaKey) return;
- if (!lunaKey) {
- // 若没有指定的组件,且当前又没有选中组件,默认选中顶部组件,如果是下钻编辑则默认选中第一个子组件
- const schema = appHelper.schemaHelper.schema;
- if (schema) {
- if (schema.componentName === 'Temp') {
- lunaKey = schema.children && schema.children[0] && schema.children[0].__ctx.lunaKey;
- } else {
- lunaKey = schema.__ctx.lunaKey;
- }
- }
- }
- appHelper.emit('material.select', lunaKey);
- };
-
- // 构造低代码组件
- generateLowComps = (props = this.props) => {
- const { components } = props;
- const { utils, constants } = this.canvasAppHelper || {};
- const componentsMap = this.appHelper.componentsMap || {};
- Object.keys(componentsMap).forEach((key) => {
- const comp = componentsMap[key];
- // 对自定义组件做特殊处理
- if (comp.version === '0.0.0' && comp.code) {
- let schema = parseObj(comp.code);
- if (isFileSchema(schema) && schema.componentName === 'Component') {
- components[comp.name] = CompFactory(schema, components, componentsMap, {
- utils,
- constants,
- });
- }
- }
- });
- return components;
- };
-
- updateCanvasAppHelper = (props = this.props) => {
- const { utils } = props;
- const { entityInfo = {}, componentsMap } = this.appHelper;
- this.canvasAppHelper.set({
- componentsMap,
- utils: entityInfo.utils ? generateUtils(utils, parseObj(entityInfo.utils)) : utils,
- constants: parseObj((entityInfo && entityInfo.constants) || {}),
- });
- this.canvasAppHelper.set('components', this.generateLowComps(props));
- };
-
- updateStyle = () => {
- const entityInfo = this.appHelper.entityInfo || {};
- const blockSchemaMap = (this.appHelper.schemaHelper && this.appHelper.schemaHelper.blockSchemaMap) || {};
- const componentsMap = this.appHelper.componentsMap || {};
- const cssMap = {};
- // 区块中的样式
- Object.keys(blockSchemaMap).forEach((item) => {
- const schema = blockSchemaMap[item];
- cssMap[schema.fileName] = schema.css || (schema.__ctx && schema.__ctx.css) || '';
- });
- // 低代码自定义组件中的样式
- Object.keys(componentsMap).forEach((item) => {
- const comp = componentsMap[item];
- // 对自定义组件做特殊处理
- if (comp.version === '0.0.0' && comp.code && comp.css) {
- cssMap[comp.name] = comp.css;
- }
- });
- cssMap.__global = entityInfo.css || '';
- if (shallowEqual(this.cacheCssMap, cssMap)) return;
- this.cacheCssMap = cssMap;
- const { __global, ...other } = cssMap;
- addCssTag(
- 'luna-canvas-style',
- `${__global}\n${Object.keys(other || {})
- .map((item) => cssMap[item])
- .join('\n')}`,
- );
- };
-
- updateCanvasStack = () => {
- const { canvasStack } = this.state;
- if (canvasStack.length < 2) return;
- for (let idx = canvasStack.length - 1; idx > 0; idx--) {
- const currentData = canvasStack[idx];
- const { lunaPath, name, schemaHelper, schema } = currentData;
- const preData = canvasStack[idx - 1];
- let data = schemaHelper.getPureSchema().children;
- // 如果情况内容则删除属性
- if (isEmpty(data)) {
- jsonuri.rm(
- preData.schemaHelper.schema,
- name === 'children' ? `${lunaPath}/children` : `${lunaPath}/props/${name.replace('.', '/')}`,
- );
- continue;
- }
- if (isJSSlot(schema)) {
- data = {
- ...schema,
- value: data,
- };
- } else if (name !== 'children') {
- data = {
- type: 'JSSlot',
- value: data,
- };
- }
- jsonuri.set(
- preData.schemaHelper.schema,
- name === 'children' ? `${lunaPath}/children` : `${lunaPath}/props/${name.replace('.', '/')}`,
- data,
- );
- }
- };
-
- updateDesignMode = (ref, schema, topLevel) => {
- if (!ref || (ref && ref.current === null) || !schema.__ctx) return;
- const { engine } = this.props;
- const appHelper = this.appHelper;
- const { activeKey, isPreview, viewPortConfig } = appHelper;
- const designMode = isPreview ? 'preview' : appHelper.designMode;
- const node = engine.findDOMNode(ref.current || ref);
-
- if (!node || !node.getAttribute) return;
- // 渲染引擎可以通过设置__disableDesignMode属性的方式阻止组件的可视模式;
- const hasDesignMode =
- [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(designMode) && !ref.props.__disableDesignMode;
- node.setAttribute('data-design-mode', designMode && hasDesignMode ? `luna-design-${designMode}` : '');
- if (topLevel) {
- node.setAttribute('top-container', true);
- }
- const lunaKey = schema.__ctx.lunaKey;
- let instanceName = schema.componentName + (window.parent.__isDebug ? (lunaKey || '_').split('_')[1] : '');
- switch (schema.componentName) {
- case 'Page':
- instanceName = '页面容器 ' + instanceName;
- break;
- case 'Block':
- instanceName = '区块容器 ' + instanceName;
- break;
- case 'Component':
- instanceName = '低代码组件容器 ' + instanceName;
- break;
- case 'Addon':
- instanceName = '插件容器 ' + instanceName;
- break;
- case 'Temp':
- instanceName = '下钻编辑器容器';
- }
-
- if (topLevel && viewPortConfig) {
- node.style.transform = `scale(${viewPortConfig.scale ? viewPortConfig.scale / 100 : 1})`;
- }
- node.setAttribute('data-instance-name', instanceName);
- node.setAttribute('data-luna-key', lunaKey);
- node.setAttribute('data-luna-path', schema.__ctx.lunaPath);
-
- if (hasDesignMode) {
- if (activeKey && activeKey === lunaKey) {
- node.setAttribute('data-active', true);
- } else {
- node.removeAttribute('data-active');
- }
- // 点击
- if (!node.compEvent && schema.componentName !== 'Temp') {
- node.compEvent = (ev) => {
- ev.stopPropagation();
- appHelper.emit('material.select', lunaKey, { isFromCanvas: true });
- };
- on(node, 'mousedown', node.compEvent, false);
- }
-
- // drag and drop
- if (!node.draggableFlag) {
- if (topLevel) {
- node.ondragleave = (ev) => this.handleDnd('DragLeave', ev, schema);
- node.ondrop = (ev) => this.handleDnd('Drop', ev, schema);
- } else {
- node.setAttribute('draggable', 'true');
- node.ondragstart = (ev) => this.handleDnd('DragStart', ev, schema);
- node.ondragend = (ev) => this.handleDnd('DragEnd', ev, schema);
- }
- node.ondragover = (ev) => this.handleDnd('DragOver', ev, schema);
- node.draggableFlag = true;
- }
- } else {
- //点击
- if (node.compEvent) {
- off(node, 'mousedown', node.compEvent, false);
- delete node.compEvent;
- }
- //drag and drop
- if (node.draggableFlag) {
- node.removeAttribute('draggable');
- delete node.ondragstart;
- delete node.ondragover;
- delete node.ondragend;
- delete node.ondragleave;
- delete node.ondrop;
- delete node.draggableFlag;
- }
- }
- };
-
- renderCanvasStack = () => {
- const { canvasStack } = this.state;
- const lastIndex = canvasStack.length - 1;
- const appHelper = this.appHelper;
- const canvasAppHelper = this.canvasAppHelper;
- const designMode = appHelper.isPreview ? 'preview' : appHelper.designMode;
- const Engine = this.props.engine;
-
- return (canvasStack || []).map((item, idx) => (
-
-
-
- ));
- };
-
- render() {
- const { canvasStack } = this.state;
- const lastIndex = canvasStack.length - 1;
- const schema = canvasStack[lastIndex] && canvasStack[lastIndex].schemaHelper.schema;
-
- const appHelper = this.appHelper;
- const { entityInfo = {}, viewPortConfig = {}, canvasPlaceholder = {} } = appHelper;
- const components = this.canvasAppHelper.components || {};
-
- const placeholder = { ...DEFAULT_PLACEHOLDER, ...canvasPlaceholder };
- const layoutComp = entityInfo.layoutInfo && entityInfo.layoutInfo.name;
- const layoutProps = (entityInfo.layoutInfo && entityInfo.layoutInfo.realProps) || {};
- const Layout = layoutComp && components[layoutComp];
- const { hideLayout } = viewPortConfig;
- const isDrillDown = canvasStack && canvasStack.length > 1;
- const isSchemaEmpty = isSchema(schema) && isEmpty(schema.children);
- const isSchemaNull = schema === null;
- const canvasStyle = {};
- if (!isDrillDown) {
- if (isSchemaEmpty) {
- canvasStyle.backgroundImage = `url(${placeholder.emptyImage})`;
- } else if (isSchemaNull) {
- canvasStyle.backgroundImage = `url(${placeholder.nullImage})`;
- }
- }
- return (
-
- {Layout && !hideLayout ? (
-
- {this.renderCanvasStack()}
-
- ) : (
- this.renderCanvasStack()
- )}
-
- );
- }
-}
diff --git a/packages/react-renderer/src/comp/canvas/index.scss b/packages/react-renderer/src/comp/canvas/index.scss
deleted file mode 100644
index 3961561d4..000000000
--- a/packages/react-renderer/src/comp/canvas/index.scss
+++ /dev/null
@@ -1,361 +0,0 @@
-/*增加标签函数*/
-@mixin labelFun($type: before) {
- &:#{$type} {
- content: attr(data-instance-name) !important;
- position: absolute;
- left: 0;
- top: 0;
- right: unset;
- bottom: unset;
- color: #666 !important;
- font-size: 12px !important;
- float: left;
- padding: 0 5px !important;
- line-height: 12px !important;
- height: 12px;
- overflow: hidden;
- background: rgba(222, 222, 222, 0.7);
- z-index: 2;
- border-left: 3px solid transparent;
- transform-origin: 0 0;
- transform: scale(0.8);
- transition: all 0.3s ease;
- }
-
- &.luna-block,
- &.luna-page,
- &.luna-comp {
- &:#{$type} {
- border-color: #2077ff;
- }
- }
-
- &[data-active='true'] {
- &:#{$type} {
- color: #fff !important;
- background: #1861d5 !important;
- }
- }
-
- &[data-design-mode='luna-design-border'] {
- &:#{$type} {
- display: none;
- }
-
- &[data-active='true'] {
- &:#{$type} {
- display: block;
- }
- }
- }
-}
-
-.luna-canvas-inner {
- height: 100%;
-
- &.empty,
- &.null {
- position: relative;
- background-repeat: no-repeat;
- background-position: calc(50% - 180px) 50%;
- background-size: 310px 215px;
-
- &:after {
- content: attr(data-placeholder-text);
- position: absolute;
- pointer-events: none;
- top: 50%;
- left: 50%;
- margin: -40px 0 0 20px;
- height: 80px;
- line-height: 40px;
- color: #aaa;
- font-size: 24px;
- white-space: pre;
- }
- }
-
- &.empty {
- &.drill-down {
- &:before {
- display: none;
- }
-
- &:after {
- content: '请拖入组件';
- text-align: center;
- left: 0;
- right: 0;
- margin-left: 0;
- font-size: 14px;
- }
- }
- }
-
- .engine-wrapper {
- height: 100%;
- display: none;
- overflow: auto;
-
- &.extend,
- &.border {
- padding: 1px;
-
- > div {
- padding: 1px;
- }
- }
-
- &:last-child {
- display: block;
- }
-
- &.fixed-width > div {
- min-width: unset;
- width: auto;
- }
-
- &.fixed-height > div {
- min-height: unset;
- }
-
- > div {
- transform-origin: left top;
- min-width: 100%;
- width: fit-content;
- min-height: 100%;
- }
- }
-}
-
-a,
-span:not(.next-input-group):not(.next-input) {
- &[data-design-mode*='luna-design-'] {
- display: inline-block;
- min-height: 16px;
- }
-}
-
-[data-luna-key] {
- transition: all 0.3s ease;
-}
-
-[data-design-mode='luna-design-border'] {
- min-height: 10px;
-}
-
-[data-design-mode='luna-design-extend'] {
- min-height: 20px;
-}
-
-[data-design-mode*='luna-design-'] {
- position: relative;
- outline: 1px dotted #d9d9d9;
- zoom: 1;
-
- &:hover {
- outline: 1px dotted #2077ff;
- }
-
- [draggable='true'] {
- position: relative;
- }
-
- .next-card-body {
- overflow: inherit !important;
- }
-
- &.next-loading {
- pointer-events: all !important;
- }
-
- &[data-active='true'] {
- outline: 1px solid #1861d5 !important;
-
- &[data-nochild='true']:not(.next-step-item):not([top-container='true']) {
- min-height: 60px;
- min-width: 200px;
-
- &:after {
- content: '请拖入组件';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- margin: auto;
- opacity: 1 !important;
- visibility: visible !important;
- line-height: 30px;
- height: 30px;
- font-size: 13px;
- color: #ccc;
- text-align: center;
- }
- }
- }
-
- &:not(.next-tag):not(.next-icon):not(.anticon):not(.icon) {
- @include labelFun(before);
- }
-
- &.next-tag,
- &.next-icon,
- &.anticon,
- &.icon {
- @include labelFun(after);
- }
-
- &.next-tabs-tabpane.hidden {
- min-height: 0;
- }
-
- &.ant-loop:after {
- content: '';
- display: block;
- clear: both;
- line-height: 0;
- }
-
- .ant-tabs-tabpane {
- padding: 1px;
- }
-
- .ide-design-placeholder {
- position: relative;
- text-align: center;
- border: 1px dashed #d9d9d9;
- outline: none;
- padding: 0 !important;
- min-height: 20px;
- min-width: 80px;
-
- &:after {
- content: attr(data-prop);
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- text-align: center;
- line-height: 20px;
- color: #e9e9e9;
- }
- }
-
- &[data-instance-name='TableGroupHeaderF'] {
- clear: both;
-
- &:after {
- content: '';
- width: 100%;
- height: 0;
- clear: both;
- overflow: hidden;
- }
- }
-
- &[data-design-mode='luna-design-extend'] {
- &[data-luna-key*='luna_'] {
- &:not([class*='-input']):not([class*='-picker']):not([class*='-table']):not([class*='-switch']):not([class*='-select']):not(img):not([class*='-btn']):not(.next-tag):not(input):not([class*='-rating']):not([class*='next-menu']) {
- padding: 10px;
- }
-
- &.ant-loop {
- padding: 10px 0 0;
- }
- }
-
- [class*='-form-item-control'] {
- & > [data-design-mode*='luna-design-'] {
- &:not(button):not(input):not([class*='-input']):not([class*='luna-comp-']) {
- padding: 0 !important;
- }
- }
- }
- }
-}
-
-#luna-canvas-effect {
- position: fixed;
- background: #1aab11;
- z-index: 10000000;
- text-align: center;
- pointer-events: none;
-
- &:before,
- &:after {
- content: '';
- position: absolute;
- width: 2px;
- height: 2px;
- border: 4px solid #1aab11;
- pointer-events: none;
- }
-
- &.left,
- &.right {
- width: 2px;
-
- &:before,
- &:after {
- left: -4px;
- border-left-color: transparent;
- border-right-color: transparent;
- }
-
- &:before {
- top: 0;
- border-bottom-width: 0;
- }
-
- &:after {
- bottom: 0;
- border-top-width: 0;
- }
- }
-
- &.top,
- &.bottom,
- &.in {
- height: 2px;
-
- &:before,
- &:after {
- top: -4px;
- border-top-color: transparent;
- border-bottom-color: transparent;
- }
-
- &:before {
- left: 0;
- border-right-width: 0;
- }
-
- &:after {
- right: 0;
- border-left-width: 0;
- }
- }
-
- &.in {
- b {
- display: inline-block;
- }
- }
-
- b {
- display: inline-block;
- position: relative;
- top: -12px;
- margin: 0 auto;
- padding: 0 10px;
- color: #fff;
- background: #1aab11;
- height: 16px !important;
- line-height: 16px !important;
- font-weight: normal;
- font-size: 11px;
- display: none;
- }
-}
diff --git a/packages/react-renderer/src/hoc/addonFactory.js b/packages/react-renderer/src/hoc/addonFactory.js
deleted file mode 100644
index 67065239b..000000000
--- a/packages/react-renderer/src/hoc/addonFactory.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-import AddonEngine from '../engine/addonEngine';
-import BlockEngine from '../engine/blockEngine';
-import AppContext from '../context/appContext';
-import { forEach, isFileSchema } from '../utils';
-export default function addonFactory(schema, components = {}, componentsMap = {}, config = {}) {
- class LNAddonView extends PureComponent {
- static dislayName = 'luna-addon-factory';
- static version = config.version || '0.0.0';
- static contextType = AppContext;
- static propTypes = {
- forwardedRef: PropTypes.func,
- };
- render() {
- if (!schema || schema.componentName !== 'Addon' || !isFileSchema(schema)) {
- console.warn('编辑器插件模型结构异常!');
- return null;
- }
- const { forwardedRef, ...otherProps } = this.props;
- const props = {
- ...schema.defaultProps,
- ...otherProps,
- __schema: schema,
- ref: forwardedRef,
- };
- return (
-
-
-
- );
- }
- }
- const ResComp = React.forwardRef((props, ref) => );
- forEach(schema.static, (val, key) => {
- ResComp[key] = val;
- });
- ResComp.version = config.version || '0.0.0';
- return ResComp;
-}
diff --git a/packages/react-renderer/src/hoc/compFactory.js b/packages/react-renderer/src/hoc/compFactory.js
deleted file mode 100644
index 49c32df7a..000000000
--- a/packages/react-renderer/src/hoc/compFactory.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import React, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-import CompEngine from '../engine/compEngine';
-import BlockEngine from '../engine/blockEngine';
-import AppContext from '../context/appContext';
-import AppHelper from '../utils/appHelper';
-import { forEach, isFileSchema } from '../utils';
-export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
- // 自定义组件需要有自己独立的appHelper
- const appHelper = new AppHelper(config);
- class LNCompView extends PureComponent {
- static dislayName = 'luna-comp-factory';
- static version = config.version || '0.0.0';
- static contextType = AppContext;
- static propTypes = {
- forwardedRef: PropTypes.func,
- };
- render() {
- if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) {
- console.warn('自定义组件模型结构异常!');
- return null;
- }
- const { forwardedRef, ...otherProps } = this.props;
- // 低代码组件透传应用上下文
- const appCtx = ['utils', 'constants'];
- appCtx.forEach((key) => {
- if (!appHelper[key] && this.context && this.context.appHelper && this.context.appHelper[key]) {
- appHelper.set(key, this.context.appHelper[key]);
- }
- });
- const routerCtx = ['history', 'location', 'match'];
- routerCtx.forEach((key) => {
- if (this.context && this.context.appHelper && this.context.appHelper[key]) {
- appHelper.set(key, this.context.appHelper[key]);
- }
- });
- // 支持通过context透传国际化配置
- const localeProps = {};
- const { locale, messages } = this.context;
- if (locale && messages && messages[schema.fileName]) {
- localeProps.locale = locale;
- localeProps.messages = messages[schema.fileName];
- }
- const props = {
- ...schema.defaultProps,
- ...localeProps,
- ...otherProps,
- __schema: schema,
- ref: forwardedRef,
- };
-
- return (
-
-
-
- );
- }
- }
-
- const ResComp = React.forwardRef((props, ref) => );
- forEach(schema.static, (val, key) => {
- ResComp[key] = val;
- });
- ResComp.version = config.version || '0.0.0';
- return ResComp;
-}
diff --git a/packages/react-renderer/src/hoc/localeConfig.js b/packages/react-renderer/src/hoc/localeConfig.js
deleted file mode 100644
index ccdfe3db4..000000000
--- a/packages/react-renderer/src/hoc/localeConfig.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-import AppContext from '../context/appContext';
-export default function localeConfig(componentName, Component) {
- class LNLocaleConfigView extends PureComponent {
- static dislayName = 'luna-locale-config';
- static contextType = AppContext;
- static propTypes = {
- forwardedRef: PropTypes.func,
- };
- render() {
- const { forwardedRef, ...otherProps } = this.props;
- const { locale, messages } = this.context;
- const localeProps = {};
- if (locale && messages && messages[componentName]) {
- localeProps.locale = locale;
- localeProps.messages = messages[componentName];
- }
- const props = {
- ...localeProps,
- ...otherProps,
- ref: forwardedRef,
- };
- return ;
- }
- }
-
- return React.forwardRef((props, ref) => );
-}
diff --git a/packages/react-renderer/src/hoc/suspenseWrapper.js b/packages/react-renderer/src/hoc/suspenseWrapper.js
deleted file mode 100644
index 6a0224af7..000000000
--- a/packages/react-renderer/src/hoc/suspenseWrapper.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React, { PureComponent, Suspense } from 'react';
-export default function SuspenseWrapper(fallback = null) {
- return function(Component) {
- class SuspenseWrapper extends PureComponent {
- render() {
- return (
-
-
-
- );
- }
- }
- return SuspenseWrapper;
- };
-}
diff --git a/packages/react-renderer/src/utils/appHelper.js b/packages/react-renderer/src/utils/appHelper.js
deleted file mode 100644
index 8bec5fa83..000000000
--- a/packages/react-renderer/src/utils/appHelper.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import EventEmitter from 'events';
-import Debug from 'debug';
-let instance = null;
-const debug = Debug('utils:appHelper');
-EventEmitter.defaultMaxListeners = 100;
-
-export default class AppHelper extends EventEmitter {
- static getInstance = () => {
- if (!instance) {
- instance = new AppHelper();
- }
- return instance;
- };
-
- constructor(config) {
- super();
- instance = this;
- Object.assign(this, config);
- }
-
- get(key) {
- return this[key];
- }
-
- set(key, val) {
- if (typeof key === 'string') {
- this[key] = val;
- } else if (typeof key === 'object') {
- Object.keys(key).forEach((item) => {
- this[item] = key[item];
- });
- }
- }
-
- batchOn(events, lisenter) {
- if (!Array.isArray(events)) return;
- events.forEach((event) => this.on(event, lisenter));
- }
-
- batchOnce(events, lisenter) {
- if (!Array.isArray(events)) return;
- events.forEach((event) => this.once(event, lisenter));
- }
-
- batchOff(events, lisenter) {
- if (!Array.isArray(events)) return;
- events.forEach((event) => this.off(event, lisenter));
- }
-}
diff --git a/packages/react-renderer/src/utils/dndHelper.js b/packages/react-renderer/src/utils/dndHelper.js
deleted file mode 100644
index 8bd20153c..000000000
--- a/packages/react-renderer/src/utils/dndHelper.js
+++ /dev/null
@@ -1,574 +0,0 @@
-import ReactDOM from 'react-dom';
-import Debug from 'debug';
-import { isFileSchema, isEmpty, throttle, deepEqual } from './index';
-const DICT = {
- left: '左',
- right: '右',
- top: '上',
- bottom: '下',
- in: '里',
-};
-const TOP_COMPONENT = ['Page', 'Component', 'Temp']; // 顶端模块,不支持放置兄弟节点
-const debug = Debug('utils:dndHelper');
-export default class DndHelper {
- constructor(appHelper) {
- this.appHelper = appHelper;
- this.dragDom = null;
- this.canvasEffectDom = null;
- this.treeEffectDom = null;
- this.containrDom = null;
- this.sourceEntity = null;
- this.tempEntity = null;
- this.dragInfo = null;
- this.canvasClearTimer = null;
- this.treeClearTimer = null;
- this.isDragging = false;
- this.dragOverFunc = throttle(this.dragOverFunc, 50);
- }
-
- setCanvasWin(win) {
- this.canvasWin = win;
- if (this.canvasEffectDom) {
- this.canvasWin.document.body.appendChild(this.canvasEffectDom);
- }
- }
-
- emit(msg, ...args) {
- this.appHelper && this.appHelper.emit(msg, ...args);
- }
-
- dragOverFunc(ev, schemaOrNode, isTree) {
- if (!this.isDragging || !this.sourceEntity) return;
- const entity = isTree
- ? this.getTreeEntity(schemaOrNode, ev)
- : {
- target: ev.currentTarget,
- schema: schemaOrNode,
- };
- if (this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaKey === entity.schema.__ctx.lunaKey)
- return;
- let dragInfo = null;
- if (isTree) {
- dragInfo = this.getTreeDragInfo(ev, entity);
- } else {
- dragInfo = this.getDragInfo(ev, entity);
- }
- if (!dragInfo || deepEqual(this.dragInfo, dragInfo)) return;
- this.dragInfo = dragInfo;
- this.tempEntity = dragInfo.entity;
- this.clearEffect(isTree);
- this.addEffect(isTree);
- }
-
- changeCanvas() {
- debug('change canvas', this.sourceEntity, this.tempEntity);
- if (!this.sourceEntity || !this.tempEntity) return;
- if (this.sourceEntity.isAdd) {
- debug('add material', this.sourceEntity.schema, this.tempEntity.schema.__ctx.lunaKey, this.dragInfo.position);
- this.emit('material.add', {
- schema: this.sourceEntity.schema,
- targetKey: this.tempEntity.schema.__ctx.lunaKey,
- direction: this.dragInfo.position,
- });
- } else {
- this.emit('material.move', {
- lunaKey: this.sourceEntity.schema.__ctx.lunaKey,
- targetKey: this.tempEntity.schema.__ctx.lunaKey,
- direction: this.dragInfo.position,
- });
- }
- }
-
- getTreeEntity(node, ev) {
- if (!node) return;
- const schemaHelper = this.appHelper.schemaHelper;
- const lunaKey = node.props.eventKey;
- const schema = schemaHelper.schemaMap[lunaKey];
- if (!schema) return;
- const ref = schemaHelper.compThisMap[lunaKey];
- const currentTarget = ev.currentTarget;
- return {
- schema,
- target: ref && ReactDOM.findDOMNode(ref),
- treeNodeTarget: currentTarget,
- };
- }
-
- getDragTagDom(tagName) {
- if (!this.dragDom) {
- const dragDom = document.createElement('div');
- dragDom.id = 'luna-drag-dom';
- dragDom.style.height = '24px';
- dragDom.style.position = 'absolute';
- dragDom.style.zIndex = 10000000;
- dragDom.style.transform = 'translateY(-10000px)';
- dragDom.style.background = 'rgba(0, 0, 0, .5)';
- dragDom.style.lineHeight = '24px';
- dragDom.style.color = '#fff';
- dragDom.style.padding = '0px 10px';
- dragDom.style.display = 'inline-block';
- document.body.appendChild(dragDom);
- this.dragDom = dragDom;
- }
- this.dragDom.innerHTML = ` ${tagName}`;
- return this.dragDom;
- }
-
- getCanvasEffectDom() {
- if (!this.canvasWin) {
- throw new Error('should set the canvasWin first');
- }
- if (this.canvasClearTimer) {
- clearTimeout(this.canvasClearTimer);
- this.canvasClearTimer = null;
- }
-
- const { position } = this.dragInfo;
- let canvasEffectDom = this.canvasEffectDom;
- if (!canvasEffectDom) {
- canvasEffectDom = document.createElement('div');
- this.canvasWin.document.body.appendChild(canvasEffectDom);
- this.canvasEffectDom = canvasEffectDom;
- }
- canvasEffectDom.id = 'luna-canvas-effect';
- canvasEffectDom.innerHTML = `${DICT[position]}`;
- canvasEffectDom.className = position;
- canvasEffectDom.style.display = 'block';
-
- return canvasEffectDom;
- }
-
- getTreeEffectDom() {
- if (this.treeClearTimer) {
- clearTimeout(this.treeClearTimer);
- this.treeClearTimer = null;
- }
- let treeEffectDom = this.treeEffectDom;
- if (!treeEffectDom) {
- treeEffectDom = document.createElement('div');
- this.treeEffectDom = treeEffectDom;
- }
- treeEffectDom.id = 'luna-tree-effect';
- treeEffectDom.style.display = 'block';
- return treeEffectDom;
- }
-
- getLunaContainerDom(target) {
- if (!target) return null;
- let parent = target.parentNode;
- while (parent && (!parent.dataset || !parent.dataset.lunaKey)) {
- parent = parent.parentNode;
- }
- return parent;
- }
-
- clearCompTreeEffect() {
- const container = document.querySelector('.luna-comp-tree');
- if (!container) return;
-
- let treeItems = container.querySelectorAll('.tree-item');
- (treeItems || []).forEach((item) => {
- const classList = item.classList;
- if (classList) {
- classList.remove('top');
- classList.remove('in');
- classList.remove('bottom');
- classList.remove('tree-item');
- }
- });
- }
-
- getDragInfo(ev, entity) {
- if (!this.sourceEntity || !entity) return null;
- const { target, schema } = entity;
- const sourcePath = this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaPath;
- const targetPath = schema.__ctx.lunaPath;
- const sourceTarget = this.sourceEntity.target;
-
- if (sourcePath === targetPath) return null;
- if (targetPath && targetPath.startsWith(sourcePath)) return null;
- const componentsMap = this.appHelper.get('componentsMap');
- // if (!componentsMap || !componentsMap[schema.componentName]) return null;
- let isContainer =
- (componentsMap[schema.componentName] && componentsMap[schema.componentName].isContainer) || isFileSchema(schema); //是否是容器组件
- if (schema.children && typeof schema.children !== 'object') {
- //如果children是文本, 非模型结构,则非容器;
- isContainer = false;
- }
- const rect = target.getBoundingClientRect();
- const isSupportIn =
- isContainer &&
- (!schema.children || (schema.children && typeof schema.children === 'object' && isEmpty(schema.children)));
- const sourceIsInline = sourceTarget && ['inline-block', 'inline'].includes(getComputedStyle(sourceTarget).display);
- const isInline = ['inline-block', 'inline'].includes(getComputedStyle(target).display) && sourceIsInline;
- const measure = isInline ? 'width' : 'height';
-
- let sn = 0;
- let position = 'top';
- if (isContainer) {
- sn = isSupportIn ? rect[measure] * 0.25 : Math.min(rect[measure] * 0.5, 10);
- } else {
- sn = rect[measure] * 0.5;
- }
- if (TOP_COMPONENT.includes(schema.componentName)) {
- // 顶端组件,拖拽over时,只能放在其内部
- position = 'in';
- } else if (isInline && !isContainer) {
- if (Math.abs(ev.clientX - rect.left) <= sn) {
- position = 'left';
- } else if (Math.abs(ev.clientX - rect.right) <= sn) {
- position = 'right';
- }
- } else {
- if (Math.abs(ev.clientY - rect.top) <= sn) {
- position = 'top';
- } else if (Math.abs(ev.clientY - rect.bottom) <= sn) {
- position = 'bottom';
- } else {
- position = 'in';
- }
- }
-
- // 判断是否是相邻元素, 往左|上拖
- const isPrevSibling = sourceTarget === target.nextElementSibling;
- if (isPrevSibling) {
- if (position === 'right') position = 'left';
- if (position === 'bottom') {
- position = isContainer ? 'in' : 'top';
- }
- }
- // 判断是否相邻元素,往右|下拖
- const isPostSibling = sourceTarget === target.previousElementSibling;
- if (isPostSibling) {
- if (position === 'left') position = 'right';
- if (position === 'top') {
- position = isContainer ? 'in' : 'bottom';
- }
- }
-
- //如果是容器组件,且包含有子组件,且是in状态,进行智能识别处理;
- let subChildren = [];
- const getChildren = (node) => {
- if (!node || !node.childNodes || node.childNodes.length === 0) return;
- node.childNodes.forEach((child) => {
- if (child === sourceTarget) return;
- if (child && child.getAttribute && child.getAttribute('draggable')) {
- const isInline = ['inline', 'inline-block'].includes(getComputedStyle(child).display) && sourceIsInline;
- const rect = child.getBoundingClientRect();
- const l = Math.abs(ev.clientX - rect.left);
- const r = Math.abs(ev.clientX - rect.right);
- const t = Math.abs(ev.clientY - rect.top);
- const b = Math.abs(ev.clientY - rect.bottom);
- const minXDistance = Math.min(l, r);
- const minYDistance = Math.min(t, b);
- subChildren.push({
- lunaKey: child.dataset.lunaKey,
- node: child,
- minDistance: isInline ? [minXDistance, minYDistance] : [minYDistance, minXDistance],
- position: isInline ? (l > r ? 'right' : 'left') : b > t ? 'top' : 'bottom',
- });
- } else {
- getChildren(child);
- }
- });
- };
- if (position === 'in' && isContainer && !isSupportIn) {
- getChildren(target);
- subChildren = subChildren.sort((a, b) => {
- if (a.minDistance[0] === b.minDistance[0]) {
- return a.minDistance[1] - b.minDistance[1];
- }
- return a.minDistance[0] - b.minDistance[0];
- });
- const tempChild = subChildren[0];
- if (tempChild) {
- if (sourceTarget === tempChild.node.nextElementSibling && ['bottom', 'right'].includes(tempChild.position))
- return null;
- if (sourceTarget === tempChild.node.previousElementSibling && ['top', 'left'].includes(tempChild.position))
- return null;
- position = tempChild.position;
- entity = {
- target: tempChild.node,
- schema: this.appHelper.schemaHelper.schemaMap[tempChild.lunaKey],
- };
- }
- }
-
- const containrDom = position === 'in' ? entity.target : this.getLunaContainerDom(entity.target);
- if (this.containrDom !== containrDom) {
- if (this.containrDom) {
- this.containrDom.style.outline = '';
- }
- this.containrDom = containrDom;
- }
- if (this.containrDom) {
- containrDom.style.outline = '1px solid #1aab11';
- }
- // debug('drag info:', position, isSupportIn, isContainer, entity);
- return {
- position,
- isSupportIn,
- isContainer,
- entity,
- };
- }
-
- getTreeDragInfo(ev, entity) {
- if (!this.sourceEntity || !entity) return null;
- const { schema, treeNodeTarget } = entity;
- const sourcePath = this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaPath;
- const targetPath = schema.__ctx.lunaPath;
- if (sourcePath === targetPath) return null;
- if (targetPath && targetPath.startsWith(sourcePath)) return null;
- const componentsMap = this.appHelper.get('componentsMap');
- // if (!componentsMap || !componentsMap[schema.componentName]) return null;
- let isContainer =
- (componentsMap[schema.componentName] && componentsMap[schema.componentName].isContainer) || isFileSchema(schema); //是否是容器组件
- if (schema.children && typeof schema.children !== 'object') {
- //如果children是文本, 非模型结构,则非容器;
- isContainer = false;
- }
- const rect = treeNodeTarget.getBoundingClientRect();
- const isSupportIn =
- isContainer &&
- (!schema.children || (schema.children && typeof schema.children === 'object' && isEmpty(schema.children)));
-
- const sn = isContainer && isSupportIn ? rect.height * 0.25 : rect.height * 0.5;
- let position = 'in';
- if (Math.abs(ev.clientY - rect.top) <= sn) {
- position = 'top';
- } else if (Math.abs(ev.clientY - rect.bottom) <= sn) {
- position = 'bottom';
- }
- return {
- position,
- isSupportIn,
- isContainer,
- entity,
- };
- }
-
- addEffect(isTree) {
- if (!this.tempEntity) return;
- const { position } = this.dragInfo;
- const { target, treeNodeTarget } = this.tempEntity;
- // this.clearCompTreeEffect();
- if (isTree) {
- //画父元素外框
- let status = true;
- let node = treeNodeTarget.parentNode;
- while (status) {
- if (node && node.parentNode) {
- if (node.parentNode.tagName == 'LI' && node.parentNode.classList.contains('next-tree-node')) {
- status = false;
- if (this.treeNodeTargetParent !== node.parentNode || position === 'in') {
- this.treeNodeTargetParent && this.treeNodeTargetParent.classList.remove('selected');
- }
- this.treeNodeTargetParent = node.parentNode;
- if (position !== 'in') this.treeNodeTargetParent.classList.add('selected');
- } else {
- node = node.parentNode;
- }
- } else {
- status = false;
- }
- }
- treeNodeTarget.appendChild(this.getTreeEffectDom());
- this.treeEffectDom.className = position;
- } else {
- const effectDom = this.getCanvasEffectDom();
- const rect = target.getBoundingClientRect();
- effectDom.style.left = (position === 'right' ? rect.right : rect.left) + 'px';
- effectDom.style.top =
- (position === 'bottom' ? rect.bottom : position === 'in' ? (rect.top + rect.bottom) / 2 : rect.top) + 'px';
- effectDom.style.height = ['top', 'in', 'bottom'].includes(position) ? '2px' : rect.height + 'px';
- effectDom.style.width = ['left', 'right'].includes(position) ? '2px' : rect.width + 'px';
- }
- }
-
- clearCanvasEffect() {
- if (this.canvasEffectDom) {
- this.canvasEffectDom.style.display = 'none';
- }
- if (this.containrDom) {
- this.containrDom.style.outline = '';
- }
- }
-
- clearTreeEffect() {
- if (this.treeEffectDom) {
- this.treeEffectDom.style.display = 'none';
- }
- if (this.treeNodeTargetParent) {
- this.treeNodeTargetParent.classList.remove('selected');
- }
- const tempTarget = this.tempEntity && this.tempEntity.treeNodeTarget;
- const classList = tempTarget && tempTarget.classList;
- if (classList) {
- classList.remove('top');
- classList.remove('bottom');
- classList.remove('in');
- classList.remove('tree-item');
- }
- }
-
- clearEffect(isTree) {
- if (this.isDragging) {
- // if (isTree) {
- if (this.treeClearTimer) {
- clearTimeout(this.treeClearTimer);
- this.treeClearTimer = null;
- }
- this.treeClearTimer = setTimeout(() => {
- this.clearTreeEffect();
- }, 300);
- // } else {
- if (this.canvasClearTimer) {
- clearTimeout(this.canvasClearTimer);
- this.canvasClearTimer = null;
- }
- this.canvasClearTimer = setTimeout(() => {
- this.clearCanvasEffect();
- }, 300);
- // }
- } else {
- // if (isTree) {
- this.clearTreeEffect();
- // } else {
- this.clearCanvasEffect();
- // }
- }
- }
-
- handleDragStart(ev, lunaKey) {
- ev.stopPropagation();
- const target = ev.currentTarget;
- target.style.filter = 'blur(2px)';
- const schema = this.appHelper.schemaHelper.schemaMap[lunaKey];
- ev.dataTransfer.setDragImage(this.getDragTagDom(schema.componentName), 0, 0);
- this.sourceEntity = {
- target,
- schema,
- };
- this.isDragging = true;
- }
-
- handleDragEnd(ev) {
- ev.stopPropagation();
- ev.preventDefault();
- this.isDragging = false;
- if (!this.sourceEntity) return;
- if (this.sourceEntity.target) {
- this.sourceEntity.target.style.filter = '';
- }
- this.clearEffect();
- }
-
- handleDragOver(ev, lunaKey) {
- ev.preventDefault();
- ev.stopPropagation();
- this.isDragging = true;
- const schema = this.appHelper.schemaHelper.schemaMap[lunaKey];
- this.dragOverFunc(
- {
- clientX: ev.clientX,
- clientY: ev.clientY,
- currentTarget: ev.currentTarget,
- },
- schema,
- );
- }
-
- handleDragLeave(ev) {
- //避免移动到treeEffectDom上的抖动
- ev.stopPropagation();
- if (!this.tempEntity) return;
- const rect = ev.target.getBoundingClientRect();
- // 如果鼠标位置还在当前元素范围内则不认为是dragLeave
- if (ev.x >= rect.left && ev.x <= rect.right && ev.y >= rect.top && ev.y <= rect.bottom) return;
- debug('canvas drag leave', ev);
- this.clearEffect();
- this.dragInfo = null;
- this.isDragging = false;
- }
-
- handleDrop(ev) {
- ev.stopPropagation();
- debug('drop+++++');
- this.isDragging = false;
- this.changeCanvas();
- this.clearEffect();
- }
-
- handleTreeDragStart(ev) {
- const { event, node } = ev;
- event.stopPropagation();
- const lunaKey = node.props.eventKey;
- const schema = this.appHelper.schemaHelper.schemaMap[lunaKey];
- if (!schema) return;
-
- event.dataTransfer.setDragImage(this.getDragTagDom(schema.componentName), 0, 0);
- this.sourceEntity = this.getTreeEntity(node, event);
- if (this.sourceEntity.target) {
- this.sourceEntity.target.style.filter = 'blur(2px)';
- }
- this.isDragging = true;
- }
-
- handleTreeDragEnd(ev) {
- const { event } = ev;
- event.stopPropagation();
- event.preventDefault();
- this.isDragging = false;
- if (!this.sourceEntity) return;
- if (this.sourceEntity.target) {
- this.sourceEntity.target.style.filter = '';
- }
- this.clearEffect(true);
- }
-
- handleTreeDragOver(ev) {
- const { event, node } = ev;
- event.preventDefault();
- event.stopPropagation();
- this.isDragging = true;
- this.dragOverFunc(
- {
- clientX: event.clientX,
- clientY: event.clientY,
- currentTarget: event.currentTarget.children[0],
- },
- node,
- true,
- );
- }
-
- handleTreeDragLeave(ev) {
- const { event } = ev;
- event.stopPropagation();
- if (!this.tempEntity) return;
- //避免移动到treeEffectDom上的抖动
- if (this.treeEffectDom && this.treeEffectDom.parentNode.parentNode === event.currentTarget) return;
- debug('++++ drag leave tree', ev, this.isDragging);
- this.clearEffect(true);
- this.isDragging = false;
- }
-
- handleTreeDrop(ev) {
- const { event } = ev;
- event.stopPropagation();
- this.isDragging = false;
- this.changeCanvas();
- this.clearEffect(true);
- }
-
- handleResourceDragStart(ev, title, schema) {
- ev.stopPropagation();
- ev.dataTransfer.setDragImage(this.getDragTagDom(title), -2, -2);
- this.sourceEntity = {
- isAdd: true,
- schema,
- };
- this.isDragging = true;
- }
-}
diff --git a/packages/react-renderer/src/utils/postMessager.js b/packages/react-renderer/src/utils/postMessager.js
deleted file mode 100644
index 05cb33bab..000000000
--- a/packages/react-renderer/src/utils/postMessager.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import EventEmitter from 'events';
-import Debug from 'debug';
-const debug = Debug('utils:postMessager');
-EventEmitter.defaultMaxListeners = 100;
-
-export class InnerMessager extends EventEmitter {
- constructor() {
- super();
- this.handleReceive = this.handleReceive.bind(this);
- window.addEventListener('message', this.handleReceive, false);
- }
-
- sendMsg(type, data, targetOrigin = '*') {
- window.parent &&
- window.parent.postMessage(
- {
- type,
- data,
- },
- targetOrigin,
- );
- }
-
- handleReceive(e) {
- if (!e.data || !e.data.type) return;
- this.emit(e.data.type, e.data.data);
- }
-
- destroy() {
- window.removeEventListener('message', this.handleReceive);
- }
-}
-
-export class OuterMessager extends EventEmitter {
- constructor(innerWindow) {
- super();
- this.innerWindow = innerWindow;
- this.handleReceive = this.handleReceive.bind(this);
- window.addEventListener('message', this.handleReceive, false);
- }
- sendMsg(type, data, targetOrigin = '*') {
- this.innerWindow &&
- this.innerWindow.postMessage(
- {
- type,
- data,
- },
- targetOrigin,
- );
- }
-
- handleReceive(e) {
- if (!e.data || !e.data.type) return;
- this.emit(e.data.type, e.data.data);
- }
- destroy() {
- window.removeEventListener('message', this.handleReceive);
- }
-}
diff --git a/packages/react-renderer/src/utils/schemaHelper.js b/packages/react-renderer/src/utils/schemaHelper.js
deleted file mode 100644
index 37c247802..000000000
--- a/packages/react-renderer/src/utils/schemaHelper.js
+++ /dev/null
@@ -1,482 +0,0 @@
-import { forEach } from '@ali/b3-one/lib/obj';
-import {
- clone,
- fastClone,
- jsonuri,
- isSchema,
- isFileSchema,
- isJSFunction,
- isJSExpression,
- parseObj,
- transformSchemaToPure,
- transformSchemaToStandard,
- isEmpty,
- moveArrayItem,
- serialize,
- deepEqual,
-} from './index';
-import Debug from 'debug';
-import compFactory from '../hoc/compFactory';
-const debug = Debug('utils:schemaHelper');
-let keyIndex = 0;
-export default class SchemaHelper {
- constructor(schema, appHelper) {
- this.appHelper = appHelper;
- this.reset(schema, true);
- }
-
- reset(schema, isInit) {
- debug('start reset');
- this.emit('schemaHelper.schema.beforeReset');
- this.schemaMap = {};
- this.blockSchemaMap = {};
- this.compThisMap = {};
- this.blockTree = {};
- this.compTreeMap = {};
- this.compCtxMap = {};
- this.rebuild(schema, isInit);
- this.emit('schemaHelper.schema.afterReset');
- }
-
- add(schema, targetKey, direction) {
- this.emit('schemaHelper.material.beforeAdd');
- const targetSchema = this.schemaMap[targetKey];
- if (isEmpty(schema) || !targetSchema) return;
- let targetPath = targetSchema.__ctx.lunaPath;
- if (targetPath === '' && direction !== 'in') {
- console.warn('add error');
- return;
- }
- let newSchema = [];
- if (Array.isArray(schema)) {
- newSchema = schema.filter((item) => isSchema(item, true));
- } else if (isSchema(schema)) {
- newSchema = [schema];
- } else {
- console.error('模型结构异常');
- return;
- }
- if (direction === 'in') {
- const targetNode = jsonuri.get(this.schema, targetPath);
- targetNode.children = (targetNode.children || []).concat(newSchema);
- //jsonuri.set(this.schema, targetPath, targetNode);
- } else {
- direction = ['left', 'top'].includes(direction) ? 'before' : 'after';
- newSchema.reverse().forEach((item) => {
- jsonuri.insert(this.schema, targetPath, item, direction);
- });
- }
- const addKey = `luna_${keyIndex + 1}`;
- this.rebuild(this.schema);
- this.emit('schemaHelper.material.afterAdd', addKey);
- return addKey;
- }
-
- remove(lunaKey) {
- this.emit('schemaHelper.material.beforeRemove');
- const schema = this.schemaMap[lunaKey];
- if (!schema) return;
- const lunaPath = schema.__ctx.lunaPath;
- if (lunaPath === '') {
- console.warn('root node can not be removed');
- return;
- }
-
- jsonuri.rm(this.schema, lunaPath);
- delete this.schemaMap[lunaKey];
- delete this.blockSchemaMap[lunaKey];
- this.rebuild(this.schema);
- this.emit('schemaHelper.material.afterRemove');
- }
-
- move(lunaKey, targetKey, direction) {
- this.emit('schemaHelper.material.beforeMove');
- debug('start move');
- const schema = this.schemaMap[lunaKey];
- const targetSchema = this.schemaMap[targetKey];
- if (!schema || !targetSchema) return;
- let lunaPath = schema.__ctx.lunaPath;
- let targetPath = targetSchema.__ctx.lunaPath;
- if (lunaPath === '' || (targetPath === '' && direction !== 'in')) {
- console.warn('move error');
- return;
- }
- const res = /(.*)\/(\d+)$/.exec(lunaPath);
- const prefix = res && res[1];
- const attr = res && res[2];
- if (!prefix || !attr) {
- console.warn('异常结构');
- return;
- }
- const sourceIdx = parseInt(attr);
- const reg = new RegExp(`^${prefix}/(\\d+)$`);
- const regRes = reg.exec(targetPath);
- const sourceParent = jsonuri.get(this.schema, prefix);
- direction = direction === 'in' ? 'in' : ['left', 'top'].includes(direction) ? 'before' : 'after';
- if (regRes && regRes[1] && direction !== 'in') {
- const distIdx = parseInt(regRes[1]);
- moveArrayItem(sourceParent, sourceIdx, distIdx, direction);
- } else {
- if (direction === 'in') {
- const targetNode = jsonuri.get(this.schema, targetPath);
- targetNode.children = targetNode.children || [];
- if (Array.isArray(targetNode.children)) {
- targetNode.children.push(schema);
- }
- jsonuri.set(this.schema, targetPath, targetNode);
- } else {
- jsonuri.insert(this.schema, targetPath, schema, direction);
- }
- sourceParent.splice(sourceIdx, 1);
- }
- this.rebuild(this.schema);
- this.emit('schemaHelper.material.afterMove');
- }
-
- //组件上移 下移
- // direction 取值 down/up
- slide(lunaKey, direction) {
- const schema = this.schemaMap[lunaKey];
- if (!schema || !direction) return;
- const lunaPath = schema.__ctx && schema.__ctx.lunaPath;
- if (!lunaPath) return;
- if (direction === 'up' && lunaPath.endsWith('/0')) return;
- const targetPath = lunaPath.replace(/\/(\d+)$/, (res, idx) => {
- return `/${direction === 'down' ? parseInt(idx) + 1 : parseInt(idx) - 1}`;
- });
- const targetSchema = this.getSchemaByPath(targetPath);
- const targetKey = targetSchema && targetSchema.__ctx && targetSchema.__ctx.lunaKey;
- if (!targetKey) return;
- this.move(lunaKey, targetKey, direction === 'down' ? 'bottom' : 'top');
- }
-
- // 快速复制
- copy(lunaKey) {
- this.emit('schemaHelper.material.beforeCopy');
- const schema = this.schemaMap[lunaKey];
- if (!schema) return;
- const newSchema = transformSchemaToPure(fastClone(schema));
- delete newSchema.__ctx;
- const addKey = this.add(newSchema, schema.__ctx.lunaKey, 'bottom');
- this.emit('schemaHelper.material.afterCopy', addKey);
- return addKey;
- }
-
- update(lunaKey, props) {
- this.emit('schemaHelper.material.beforeUpdate');
- const schema = this.schemaMap[lunaKey];
- if (!schema) return;
- const {
- __state,
- __defaultProps,
- __fileName,
- __scss,
- __loop,
- __loopArgs,
- __condition,
- __lifeCycles,
- __methods,
- __dataSource,
- children,
- ...otherProps
- } = props;
- debug('update props', props);
-
- //自定义组件才处理defaultProps
- if (schema.componentName === 'Component' && '__defaultProps' in props) {
- if (!__defaultProps || typeof __defaultProps !== 'object' || isEmpty(__defaultProps)) {
- delete schema.defaultProps;
- } else {
- schema.defaultProps = __defaultProps;
- }
- this.appHelper.components[schema.fileName.replace(/^\w/, (a) => a.toUpperCase())] = compFactory(schema);
- }
-
- // 如果loop值没有设置有效值,则删除schema中这个的字段
- if ('__loop' in props) {
- if (!__loop || isEmpty(__loop)) {
- delete schema.loop;
- } else {
- schema.loop = __loop;
- }
- }
-
- // 指定循环上下文变量名
- if ('__loopArgs' in props) {
- if (
- __loopArgs === undefined ||
- (typeof __loopArgs === 'object' && isEmpty(__loopArgs)) ||
- !Array.isArray(__loopArgs) ||
- __loopArgs.every((item) => !item)
- ) {
- delete schema.loopArgs;
- } else {
- schema.loopArgs = __loopArgs;
- }
- }
-
- // 判断条件
- if ('__condition' in props) {
- if (__condition === undefined) {
- delete schema.condition;
- } else {
- schema.condition = __condition;
- }
- }
-
- // 处理容器类组件需要考虑的字段
- if (isFileSchema(schema)) {
- // filename
- if ('__fileName' in props) {
- schema.fileName = __fileName;
- }
- // state
- if ('__state' in props) {
- // 重走生命周期
- schema.__ctx && ++schema.__ctx.idx;
- if (!__state || typeof __state !== 'object' || isEmpty(__state)) {
- delete schema.state;
- } else {
- schema.state = __state;
- }
- }
- // 生命周期
- if ('__lifeCycles' in props) {
- if (!__lifeCycles || typeof __lifeCycles !== 'object' || isEmpty(__lifeCycles)) {
- delete schema.lifeCycles;
- } else {
- schema.lifeCycles = __lifeCycles;
- }
- }
- // 自定义方法
- if ('__methods' in props) {
- if (!__methods || typeof __methods !== 'object' || isEmpty(__methods)) {
- delete schema.methods;
- } else {
- schema.methods = __methods;
- }
- }
-
- // 数据源设置
- if ('__dataSource' in props) {
- if (this.needContainerReload(schema.dataSource, __dataSource)) {
- schema.__ctx && ++schema.__ctx.idx;
- }
- if (__dataSource === undefined || (typeof __dataSource === 'object' && isEmpty(__dataSource))) {
- delete schema.dataSource;
- } else {
- schema.dataSource = __dataSource;
- }
- }
-
- // 如果scss值没有设置有效值,则删除schema中这个的字段
- if ('__scss' in props) {
- if (!__scss) {
- delete schema.scss;
- } else {
- schema.scss = __scss;
- }
- }
- }
-
- // 子组件
- if ('children' in props) {
- if (children === undefined || (typeof children === 'object' && isEmpty(children))) {
- delete schema.children;
- } else {
- schema.children = children;
- }
- }
-
- schema.props = {
- ...schema.props,
- ...otherProps,
- };
-
- //过滤undefined属性
- Object.keys(schema.props).map((key) => {
- if (schema.props[key] === undefined) {
- delete schema.props[key];
- }
- });
-
- this.rebuild(this.schema);
- this.emit('schemaHelper.material.afterUpdate');
- }
-
- createSchema(componentName, props, isContainer) {
- const schema = {
- componentName,
- props: props || {},
- __ctx: {
- lunaKey: ++this.lunaKey,
- },
- };
- if (isContainer) {
- schema.children = [];
- }
- return schema;
- }
-
- rebuild(schema, isInit) {
- if (!isFileSchema(schema)) {
- debug('top schema should be a file type');
- //对于null的schema特殊处理一下
- if (schema === null) {
- this.schema = schema;
- this.emit(`schemaHelper.schema.${isInit ? 'afterInit' : 'afterUpdate'}`);
- }
- return;
- }
- this.blockTree = null;
- this.compTreeMap = {};
- this.compTree = null;
- this.schemaMap = {};
- this.blockSchemaMap = {};
- this.compCtxMap = {};
- const buildSchema = (schema, parentBlockNode, parentCompNode, path = '') => {
- if (Array.isArray(schema)) {
- return schema.map((item, idx) => buildSchema(item, parentBlockNode, parentCompNode, `${path}/${idx}`));
- } else if (typeof schema === 'object') {
- // 对于undefined及null直接返回
- if (!schema) return schema;
- //JSFunction转函数
- if (isJSFunction(schema)) {
- if (typeof schema.value === 'string') {
- let tarFun = parseObj(schema.value);
- if (typeof tarFun === 'function') {
- return tarFun;
- }
- } else if (typeof schema.value === 'function') {
- return schema.value;
- }
- return schema;
- }
- //如果是对象且是JSExpression
- if (isJSExpression(schema)) {
- return '{{' + schema.value + '}}';
- }
- const res = {};
- if (isSchema(schema)) {
- res.__ctx = schema.__ctx;
- if (!res.__ctx) {
- const lunaKey = `luna_${++keyIndex}`;
- res.__ctx = {
- idx: 0,
- lunaKey,
- lunaPath: path,
- parentKey: parentCompNode && parentCompNode.lunaKey,
- blockKey: parentBlockNode && parentBlockNode.lunaKey,
- };
- } else {
- res.__ctx.lunaPath = path;
- }
- const label = schema.componentName + (schema.fileName ? '-' + schema.fileName : '');
- const lunaKey = res.__ctx && res.__ctx.lunaKey;
- this.schemaMap[lunaKey] = res;
- if (isFileSchema(schema)) {
- this.blockSchemaMap[lunaKey] = res;
-
- const blockNode = {
- label,
- lunaKey,
- isFile: true,
- children: [],
- };
- this.compTreeMap[lunaKey] = blockNode;
- const compNode = clone(blockNode);
- if (parentBlockNode) {
- parentBlockNode.children.push(blockNode);
- } else {
- this.blockTree = blockNode;
- }
- parentBlockNode = blockNode;
- if (parentCompNode) {
- parentCompNode.children.push(compNode);
- } else {
- this.compTree = compNode;
- }
- parentCompNode = compNode;
- } else {
- const compNode = {
- label,
- lunaKey,
- children: [],
- };
- parentCompNode.children.push(compNode);
- parentCompNode = compNode;
- }
- }
- forEach(schema, (val, key) => {
- if (key.startsWith('__')) {
- res[key] = val;
- } else {
- res[key] = buildSchema(val, parentBlockNode, parentCompNode, `${path}/${key}`);
- }
- });
- return res;
- }
- return schema;
- };
- this.emit(`schemaHelper.schema.${isInit ? 'beforeInit' : 'beforeUpdate'}`);
- this.schema = buildSchema(schema);
- this.emit(`schemaHelper.schema.${isInit ? 'afterInit' : 'afterUpdate'}`);
- }
-
- needContainerReload(preData = {}, nextData = {}) {
- if (
- typeof preData.dataHandler === 'function' &&
- typeof nextData.dataHandler === 'function' &&
- preData.dataHandler.toString() !== nextData.dataHandler.toString()
- ) {
- return true;
- } else if (preData.dataHandler !== nextData.dataHandler) {
- return true;
- }
- return !deepEqual(
- (preData.list || []).filter((item) => item.isInit),
- (nextData.list || []).filter((item) => item.isInit),
- (pre, next) => {
- if (typeof pre === 'function' && next === 'function') {
- return pre.toString() === next.toString();
- }
- },
- );
- }
-
- emit(msg, ...args) {
- this.appHelper && this.appHelper.emit(msg, ...args);
- }
-
- get(key) {
- return this[key];
- }
-
- getSchemaByPath(path) {
- return jsonuri.get(this.schema, path);
- }
-
- getSchema() {
- return this.schema;
- }
-
- getPureSchema() {
- return transformSchemaToPure(this.schema);
- }
-
- getPureSchemaStr() {
- return serialize(this.getPureSchema(), {
- unsafe: true,
- });
- }
-
- getStandardSchema() {
- return transformSchemaToStandard(this.schema);
- }
-
- getStandardSchemaStr() {
- return serialize(this.getStandardSchema(), {
- unsafe: true,
- });
- }
-}
diff --git a/packages/react-renderer/src/utils/storageHelper.js b/packages/react-renderer/src/utils/storageHelper.js
deleted file mode 100644
index 7c815b0d6..000000000
--- a/packages/react-renderer/src/utils/storageHelper.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import localforage from 'localforage';
-import Debug from 'debug';
-import { serialize } from './index';
-
-const debug = Debug('utils:storageHelper');
-export default class StorageHelper {
- constructor(name) {
- this.store = localforage.createInstance(name);
- }
-
- getItem(key) {
- if (!this.store) {
- throw new Error('store instance not exist');
- }
- return this.store.getItem(key);
- }
-
- setItem(key, value) {
- if (!this.store) {
- throw new Error('store instance not exist');
- }
- return this.store.setItem(key, value);
- }
-
- removeItem(key) {
- if (!this.store) {
- throw new Error('store instance not exist');
- }
- return this.store.removeItem(key);
- }
-
- clear() {
- if (!this.store) {
- throw new Error('store instance not exist');
- }
- return this.store.clear();
- }
-
- addHistory(key, code, limit = 10) {
- return new Promise((resolve, reject) => {
- key = '__luna_history_' + key;
- this.store
- .getItem(key)
- .then((res) => {
- let codeStr = serialize(code, {
- unsafe: true,
- });
- if (res && res[0] && res[0].code) {
- if (codeStr === res[0].code) return;
- }
- res = res || [];
- let newId = 1;
- if (res && res[0] && res[0].id) {
- newId = res[0].id + 1;
- }
- res.unshift({
- id: newId,
- time: +new Date(),
- code: codeStr,
- });
- this.store
- .setItem(key, res.slice(0, limit))
- .then((res) => {
- resolve(res);
- })
- .catch(reject);
- })
- .catch(reject);
- });
- }
-
- getHistory(key) {
- key = '__luna_history_' + key;
- return this.store.getItem(key);
- }
-
- clearHistory(key) {
- key = '__luna_history_' + key;
- this.store.removeItem(key);
- }
-}
diff --git a/packages/react-renderer/src/utils/undoRedoHelper.js b/packages/react-renderer/src/utils/undoRedoHelper.js
deleted file mode 100644
index 4cd352591..000000000
--- a/packages/react-renderer/src/utils/undoRedoHelper.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import Debug from 'debug';
-import { fastClone } from './index';
-const DEFAULT_CONFIG = {
- limit: 20,
-};
-const debug = Debug('utils:undoRedoHelper');
-export default class UndoRedoHelper {
- constructor(config) {
- this.config = { ...DEFAULT_CONFIG, ...config };
- this.data = {};
- }
-
- create(key, value, forceCreate) {
- if (!this.data[key] || forceCreate) {
- this.data[key] = {
- list: [fastClone(value)],
- idx: 0,
- };
- }
- return this.data[key];
- }
-
- delete(key) {
- delete this.data[key];
- }
-
- resetRecord(key, value) {
- const data = this.data[key];
- if (!data || !data.list) return;
- data.list = data.list.slice(0, data.idx + 1);
- data.list[data.idx] = fastClone(value);
- }
-
- record(key, value) {
- const data = this.data[key];
- const limit = this.config.limit;
- if (!data || !data.list) return;
- data.list = data.list.slice(0, data.idx + 1);
- if (data.list.length >= limit) {
- data.list.shift();
- }
- data.list.push(fastClone(value));
- ++data.idx;
- }
-
- undo(key) {
- const data = this.data[key];
- if (!data || !data.list) return null;
- //若没有前置操作,返回当前数据
- if (data.idx <= 0) return data.list[data.idx];
- --data.idx;
- return data.list[data.idx];
- }
- redo(key) {
- const data = this.data[key];
- if (!data || !data.list) return null;
- //若没有后续操作,返回当前数据
- if (data.idx >= data.list.length - 1) return data.list[data.idx];
- ++data.idx;
- return data.list[data.idx];
- }
-
- past(key) {
- const data = this.data[key];
- if (!data || !data.list || data.idx <= 0) return null;
- return data.list[data.idx - 1];
- }
-
- present(key) {
- const data = this.data[key];
- if (!data || !data.list) return null;
- return data.list[data.idx];
- }
-
- future(key) {
- const data = this.data[key];
- if (!data || !data.list || data.idx >= data.list.length - 1) return null;
- return data.list[data.idx + 1];
- }
-
- get(key) {
- return {
- past: this.past(key),
- present: this.present(key),
- future: this.future(key),
- };
- }
-}
diff --git a/packages/react-renderer/src/utils/wsHelper.js b/packages/react-renderer/src/utils/wsHelper.js
deleted file mode 100644
index 436080a4d..000000000
--- a/packages/react-renderer/src/utils/wsHelper.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import Debug from 'debug';
-import client from 'socket.io-client';
-import { parseUrl } from '@ali/b3-one/lib/url';
-const debug = Debug('utils:wsHelper');
-
-export default class WSHelper {
- constructor(appHelper, namespace, options) {
- this.appHelper = appHelper;
- this.ws = null;
- this.init(namespace, options);
- }
-
- init(namespace = '/', options = {}) {
- if (this.ws) {
- this.close();
- }
- const urlInfo = parseUrl();
- const ws = (this.ws = client(namespace, {
- reconnectionDelay: 3000,
- transports: ['websocket'],
- query: urlInfo.params,
- ...options,
- }));
- const appHelper = this.appHelper;
- debug('ws.init');
-
- ws.on('connect', (msg) => {
- appHelper.emit('wsHelper.connect.success', msg);
- debug('ws.connect');
- });
-
- ws.on('error', (msg) => {
- appHelper.emit('wsHelper.connect.error', msg);
- debug('ws.error', msg);
- });
-
- ws.on('disconnect', (msg) => {
- appHelper.emit('wsHelper.connect.break', msg);
- debug('ws.disconnect', msg);
- });
-
- ws.on('reconnecting', (msg) => {
- appHelper.emit('wsHelper.connect.retry', msg);
- debug('ws.reconnecting', msg);
- });
-
- ws.on('ping', (msg) => {
- debug('ws.ping', msg);
- });
-
- ws.on('pong', (msg) => {
- debug('ws.pong', msg);
- });
-
- ws.on('data', (msg) => {
- appHelper.emit('wsHelper.data.receive', msg);
- if (msg.eventName) {
- appHelper.emit(`wsHelper.result.${msg.eventName}`, msg);
- }
- debug('ws.data', msg);
- });
- }
-
- close() {
- if (!this.ws) return;
- this.ws.close();
- this.ws = null;
- this.appHelper.emit('wsHelper.connect.close');
- }
-
- send(eventName, ...args) {
- return new Promise((resolve, reject) => {
- try {
- this.appHelper.emit('wsHelper.data.request', {
- eventName,
- params: args,
- });
- this.appHelper.once(`wsHelper.result.${eventName}`, resolve);
- this.ws && this.ws.emit(eventName, ...args);
- debug('ws.send', eventName);
- } catch (err) {
- console.error('websocket error:', err);
- reject(err);
- }
- });
- }
-}
diff --git a/packages/runtime/package.json b/packages/runtime/package.json
index 161c6a4c4..2c667549f 100644
--- a/packages/runtime/package.json
+++ b/packages/runtime/package.json
@@ -1,6 +1,6 @@
{
"name": "@ali/lowcode-runtime",
- "version": "0.8.10",
+ "version": "0.8.12",
"description": "Runtime for Ali lowCode engine",
"files": [
"es",
@@ -25,7 +25,8 @@
},
"license": "MIT",
"dependencies": {
- "@ali/recore": "^1.6.9"
+ "@ali/recore": "^1.6.9",
+ "@ali/offline-events": "^1.0.0"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
diff --git a/packages/runtime/src/core/container.ts b/packages/runtime/src/core/container.ts
index 677fd32ad..e8deee816 100644
--- a/packages/runtime/src/core/container.ts
+++ b/packages/runtime/src/core/container.ts
@@ -8,7 +8,7 @@ export interface ILayoutOptions {
export default class Container {
private renderer: ReactType | null = null;
- private layouts: { [key: string]: ReactType } = {};
+ private layouts: { [key: string]: { content: ReactType; props: any } } = {};
private loading: ReactType | null = null;
private provider: any;
@@ -20,11 +20,11 @@ export default class Container {
if (!options) {
return;
}
- const { componentName } = options;
+ const { componentName, props = {} } = options;
if (!componentName || !Layout) {
return;
}
- this.layouts[componentName] = Layout;
+ this.layouts[componentName] = { content: Layout, props };
}
registerLoading(component: ReactType) {
diff --git a/packages/runtime/src/core/index.ts b/packages/runtime/src/core/index.ts
index 076fbc2ce..6160a6a20 100644
--- a/packages/runtime/src/core/index.ts
+++ b/packages/runtime/src/core/index.ts
@@ -1,5 +1,6 @@
import { ReactType } from 'react';
import Container, { ILayoutOptions } from './container';
+import { IProvider } from './provider';
import run from './run';
class App {
@@ -41,7 +42,7 @@ class App {
return this.container.getLoading();
}
- getProvider() {
+ getProvider(): IProvider {
return this.container.getProvider();
}
}
diff --git a/packages/runtime/src/core/provider/index.ts b/packages/runtime/src/core/provider/index.ts
index fb3512c68..79016f2ab 100644
--- a/packages/runtime/src/core/provider/index.ts
+++ b/packages/runtime/src/core/provider/index.ts
@@ -1,4 +1,5 @@
import { IAppConfig, IUtils, IComponents, HistoryMode } from '../run';
+import EventEmitter from '@ali/offline-events';
interface IConstants {
[key: string]: any;
@@ -100,15 +101,18 @@ export interface I18n {
type Locale = 'zh-CN' | 'en-US';
-// export interface IProvider {
-// init?(): void;
-// getAppData?(appkey: string): Promise;
-// getPageData?(pageId: string): Promise;
-// getLazyComponent?(pageId: string, props: any): any;
-// createApp?(): void;
-// }
+export interface IProvider {
+ init(): void;
+ ready(): void;
+ onReady(cb: any): void;
+ async(): Promise;
+ getAppData(): Promise;
+ getPageData(pageId: string): Promise;
+ getLazyComponent(pageId: string, props: any): any;
+ createApp(): void;
+}
-export default class Provider {
+export default class Provider implements IProvider {
private components: IComponents = {};
private utils: IUtils = {};
private constants: IConstants = {};
@@ -118,7 +122,10 @@ export default class Provider {
private history: HistoryMode = 'hash';
private containerId = '';
private i18n: I18n | null = null;
+ private homePage = '';
private lazyElementsMap: { [key: string]: any } = {};
+ private sectionalRender = false;
+ private emitter: EventEmitter = new EventEmitter();
constructor() {
this.init();
@@ -153,8 +160,24 @@ export default class Provider {
});
}
- async init() {
+ init() {
console.log('init');
+ // 默认 ready,当重载了init时需手动触发 this.ready()
+ this.ready();
+ }
+
+ ready(params?: any) {
+ if (params && typeof params === 'function') {
+ params = params();
+ }
+ this.emitter.emit('ready', params || '');
+ }
+
+ onReady(cb: (params?: any) => void) {
+ if (!cb || typeof cb !== 'function') {
+ return;
+ }
+ this.emitter.on('ready', cb);
}
getAppData(): any {
@@ -230,7 +253,7 @@ export default class Provider {
this.containerId = id;
}
- setI18n(i18n: I18n) {
+ setI18n(i18n: I18n | undefined) {
if (!i18n) {
return;
}
@@ -244,6 +267,16 @@ export default class Provider {
this.lazyElementsMap[pageId] = cache;
}
+ setHomePage(pageId: string) {
+ if (pageId) {
+ this.homePage = pageId;
+ }
+ }
+
+ setSectionalRender() {
+ this.sectionalRender = true;
+ }
+
getComponents() {
return this.components;
}
@@ -305,10 +338,18 @@ export default class Provider {
return locale ? this.i18n[locale] : this.i18n;
}
+ getHomePage() {
+ return this.homePage;
+ }
+
getlazyElement(pageId: string) {
if (!pageId) {
return;
}
return this.lazyElementsMap[pageId];
}
+
+ isSectionalRender() {
+ return this.sectionalRender;
+ }
}
diff --git a/packages/runtime/src/core/provider/react/index.ts b/packages/runtime/src/core/provider/react/index.ts
index 3bff84f94..1c0a3fb07 100644
--- a/packages/runtime/src/core/provider/react/index.ts
+++ b/packages/runtime/src/core/provider/react/index.ts
@@ -1,4 +1,4 @@
-import { createElement, ReactElement } from 'react';
+import { createElement, ReactType, ReactElement } from 'react';
import { Router } from '@ali/recore';
import app from '../../index';
import Provider from '..';
@@ -7,33 +7,66 @@ import LazyComponent from './lazy-component';
export default class ReactProvider extends Provider {
// 定制构造根组件的逻辑,如切换路由机制
createApp() {
+ const RouterView = this.getRouterView();
+ let App;
+ const layoutConfig = this.getLayoutConfig();
+ if (!layoutConfig || !layoutConfig.componentName) {
+ App = (props: any) => (RouterView ? createElement(RouterView, { ...props }) : null);
+ return App;
+ }
+ const { componentName: layoutName, props: layoutProps } = layoutConfig;
+ const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {};
+ const sectionalRender = this.isSectionalRender();
+ if (!sectionalRender && Layout) {
+ App = (props: any) =>
+ createElement(
+ Layout,
+ { ...layoutProps, ...extraLayoutProps },
+ RouterView ? createElement(RouterView, props) : null,
+ );
+ } else {
+ App = (props: any) => (RouterView ? createElement(RouterView, props) : null);
+ }
+ return App;
+ }
+
+ // 内置实现 for 动态化渲染
+ getRouterView(): ReactType | null {
const routerConfig = this.getRouterConfig();
if (!routerConfig) {
- return;
+ return null;
}
- const routes: Array<{ path: string; children: any; exact: boolean; keepAlive: boolean }> = [];
- let homePageId = '';
+ const routes: Array<{
+ path: string;
+ children: any;
+ exact: boolean;
+ defined: { keepAlive: boolean; [key: string]: any };
+ }> = [];
+ let homePageId = this.getHomePage();
Object.keys(routerConfig).forEach((pageId: string, idx: number) => {
if (!pageId) {
return;
}
const path = routerConfig[pageId];
- if (idx === 0 || path === '/') {
- homePageId = pageId;
- }
routes.push({
path,
children: (props: any) => this.getLazyComponent(pageId, props),
exact: true,
- keepAlive: true,
+ defined: { keepAlive: true },
});
+ if (homePageId) {
+ return;
+ }
+ if (idx === 0 || path === '/') {
+ homePageId = pageId;
+ }
});
if (homePageId) {
routes.push({
path: '**',
children: (props: any) => this.getLazyComponent(homePageId, { ...props }),
exact: true,
- keepAlive: true,
+ defined: { keepAlive: true },
});
}
const RouterView = (props: any) => {
@@ -45,20 +78,7 @@ export default class ReactProvider extends Provider {
...props,
});
};
- let App;
- const layoutConfig = this.getLayoutConfig();
- if (!layoutConfig || !layoutConfig.componentName) {
- App = (props: any) => createElement(RouterView, { ...props });
- return App;
- }
- const { componentName: layoutName, props: layoutProps } = layoutConfig;
- const Layout = app.getLayout(layoutName);
- if (Layout) {
- App = (props: any) => createElement(Layout, layoutProps, RouterView({ props }));
- } else {
- App = (props: any) => createElement(RouterView, props);
- }
- return App;
+ return RouterView;
}
getLazyComponent(pageId: string, props: any): ReactElement | null {
diff --git a/packages/runtime/src/core/provider/react/lazy-component.tsx b/packages/runtime/src/core/provider/react/lazy-component.tsx
index 72119ccb8..37c111097 100644
--- a/packages/runtime/src/core/provider/react/lazy-component.tsx
+++ b/packages/runtime/src/core/provider/react/lazy-component.tsx
@@ -38,6 +38,6 @@ export default class LazyComponent extends Component {
// loading扩展点
return createElement(Loading);
}
- return createElement(Renderer as any, { schema, ...restProps });
+ return createElement(Renderer as any, { schema, loading: Loading ? createElement(Loading) : null, ...restProps });
}
}
diff --git a/packages/runtime/src/core/run.ts b/packages/runtime/src/core/run.ts
index 3fd4a364e..7cc7ab98f 100644
--- a/packages/runtime/src/core/run.ts
+++ b/packages/runtime/src/core/run.ts
@@ -46,21 +46,20 @@ function transformConfig(config: IAppConfig | (() => IAppConfig)): IRecoreAppCon
};
}
-export default function run(config?: IAppConfig | (() => IAppConfig)) {
+export default function run() {
const provider = app.getProvider();
- if (config) {
- config = transformConfig(config);
- const App = provider.createApp();
- runApp(App, config);
- return;
+ if (!provider) {
+ throw new Error('');
}
- const promise = provider.async();
- promise.then((config: IAppConfig) => {
- if (!config) {
- return;
- }
- const App = provider.createApp();
- config = transformConfig(config);
- runApp(App, config);
+ provider.onReady(() => {
+ const promise = provider.async();
+ promise.then((config: IAppConfig) => {
+ if (!config) {
+ return;
+ }
+ const App = provider.createApp();
+ config = transformConfig(config);
+ runApp(App, config);
+ });
});
}