diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fa58d70
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,95 @@
+# project custom
+build
+dist
+
+
+# IDE
+.vscode
+.idea
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+lib
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# mac config files
+.DS_Store
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000..24c5859
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ printWidth: 100,
+ tabWidth: 2,
+ semi: true,
+ singleQuote: true,
+ trailingComma: 'all',
+};
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b4ab67e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+## Low-Code Engine Demo
+
+本 demo 是一个组合内核、setter、插件、物料的示范工程,因为未经长期生产环境打磨,可能还会有一些各个模块间结合的 bug,希望大家理解~
+
+更多参考资料:
+
+- [马上玩一下](https://alifd.alicdn.com/npm/@alilc/lowcode-demo@1.0.0/build/index.html)
+- [低代码引擎官网](http://lowcode-engine.cn)
+- [引擎主包](https://github.com/alibaba/lowcode-engine)
\ No newline at end of file
diff --git a/build.json b/build.json
new file mode 100644
index 0000000..97f03d4
--- /dev/null
+++ b/build.json
@@ -0,0 +1,38 @@
+{
+ "entry": {
+ "index": "src/index"
+ },
+ "vendor": false,
+ "devServer": {
+ "hot": false
+ },
+ "publicPath": "/",
+ "externals": {
+ "react": "var window.React",
+ "react-dom": "var window.ReactDOM",
+ "prop-types": "var window.PropTypes",
+ "@alifd/next": "var window.Next",
+ "@alilc/lowcode-engine": "var window.AliLowCodeEngine",
+ "@alilc/lowcode-editor-core": "var window.AliLowCodeEngine.common.editorCabin",
+ "@alilc/lowcode-editor-skeleton": "var window.AliLowCodeEngine.common.skeletonCabin",
+ "@alilc/lowcode-designer": "var window.AliLowCodeEngine.common.designerCabin",
+ "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
+ "@ali/lowcode-engine": "var window.AliLowCodeEngine",
+ "moment": "var window.moment",
+ "lodash": "var window._"
+ },
+ "plugins": [
+ [
+ "build-plugin-react-app"
+ ],
+ [
+ "build-plugin-moment-locales",
+ {
+ "locales": [
+ "zh-cn"
+ ]
+ }
+ ],
+ "./build.plugin.js"
+ ]
+}
diff --git a/build.plugin.js b/build.plugin.js
new file mode 100644
index 0000000..12882de
--- /dev/null
+++ b/build.plugin.js
@@ -0,0 +1,58 @@
+const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
+
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+module.exports = ({ onGetWebpackConfig }) => {
+ onGetWebpackConfig((config) => {
+ config.resolve.plugin('tsconfigpaths').use(TsconfigPathsPlugin, [
+ {
+ configFile: './tsconfig.json',
+ },
+ ]);
+
+ config.merge({
+ node: {
+ fs: 'empty',
+ },
+ });
+ config.merge({
+ entry: {
+ index: require.resolve('./src/index.ts'),
+ preview: require.resolve('./src/preview.tsx'),
+ },
+ });
+ config
+ .plugin('index')
+ .use(HtmlWebpackPlugin, [
+ {
+ inject: false,
+ templateParameters: {
+ },
+ template: require.resolve('./public/index.html'),
+ filename: 'index.html',
+ },
+ ]);
+ config
+ .plugin('preview')
+ .use(HtmlWebpackPlugin, [
+ {
+ inject: false,
+ templateParameters: {
+ },
+ template: require.resolve('./public/preview.html'),
+ filename: 'preview.html',
+ },
+ ]);
+
+ config.plugins.delete('hot');
+ config.devServer.hot(false);
+
+ config.module // fixes https://github.com/graphql/graphql-js/issues/1272
+ .rule('mjs$')
+ .test(/\.mjs$/)
+ .include
+ .add(/node_modules/)
+ .end()
+ .type('javascript/auto');
+ });
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..33ac6c4
--- /dev/null
+++ b/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@alilc/lowcode-demo",
+ "version": "1.0.0-beta.1",
+ "description": "Low-Code Engine 低代码搭建引擎 Demo 项目",
+ "repository": "git@github.com:alibaba/lowcode-demo.git",
+ "license": "MIT",
+ "main": "index.js",
+ "scripts": {
+ "start": "build-scripts start --disable-reload",
+ "build": "build-scripts build",
+ "pub": "node ./scripts/watchdog.js && npm pub"
+ },
+ "files": [
+ "build"
+ ],
+ "config": {},
+ "dependencies": {
+ "@alilc/lowcode-plugin-code-editor": "^1.0.1",
+ "@alilc/lowcode-plugin-code-generator": "^1.0.0",
+ "@alilc/lowcode-plugin-components-pane": "^1.0.2",
+ "@alilc/lowcode-plugin-datasource-pane": "^1.0.0",
+ "@alilc/lowcode-plugin-inject": "^1.0.0",
+ "@alilc/lowcode-plugin-manual": "^1.0.0",
+ "@alilc/lowcode-plugin-schema": "^1.0.0",
+ "@alilc/lowcode-plugin-simulator-select": "^1.0.0",
+ "@alilc/lowcode-plugin-undo-redo": "^1.0.0",
+ "@alilc/lowcode-plugin-zh-en": "^1.0.0",
+ "@alilc/lowcode-react-renderer": "^1.0.0",
+ "@alilc/lowcode-setter-behavior": "^1.0.0",
+ "@alilc/lowcode-setter-title": "^1.0.2"
+ },
+ "devDependencies": {
+ "@alilc/lowcode-engine": "^1.0.0",
+ "@alilc/lowcode-types": "^1.0.0",
+ "@alib/build-scripts": "^0.1.18",
+ "@types/events": "^3.0.0",
+ "@types/react": "^16.8.3",
+ "@types/react-dom": "^16.8.2",
+ "@types/streamsaver": "^2.0.0",
+ "build-plugin-fusion": "^0.1.0",
+ "build-plugin-moment-locales": "^0.1.0",
+ "build-plugin-react-app": "^1.1.2",
+ "tsconfig-paths-webpack-plugin": "^3.2.0"
+ }
+}
diff --git a/public/assets.json b/public/assets.json
new file mode 100644
index 0000000..1584ef9
--- /dev/null
+++ b/public/assets.json
@@ -0,0 +1,139 @@
+{
+ "packages": [
+ {
+ "package": "moment",
+ "version": "2.24.0",
+ "urls": [
+ "https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"
+ ],
+ "library": "moment"
+ },
+ {
+ "package": "lodash",
+ "library": "_",
+ "urls": [
+ "https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"
+ ]
+ },
+ {
+ "title": "fusion组件库",
+ "package": "@alifd/next",
+ "version": "1.24.18",
+ "urls": [
+ "https://g.alicdn.com/code/lib/alifd__next/1.24.18/next.min.css",
+ "https://g.alicdn.com/code/lib/alifd__next/1.24.18/next-with-locales.min.js"
+ ],
+ "library": "Next"
+ },
+ {
+ "title": "NextTable",
+ "package": "NextTable",
+ "version": "1.0.1",
+ "urls": [
+ "https://g.alicdn.com/fusion-platform/pro-table/1.0.1/next-table.js",
+ "https://g.alicdn.com/fusion-platform/pro-table/1.0.1/next-table.css"
+ ],
+ "library": "NextTable"
+ },
+ {
+ "package": "@alilc/lowcode-materials",
+ "version": "1.0.1",
+ "library": "AlilcLowcodeMaterials",
+ "urls": [
+ "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/dist/AlilcLowcodeMaterials.js",
+ "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/dist/AlilcLowcodeMaterials.css"
+ ],
+ "editUrls": [
+ "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/build/lowcode/view.js",
+ "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/build/lowcode/view.css"
+ ]
+ },
+ {
+ "package": "@alifd/pro-layout",
+ "version": "1.0.1-beta.5",
+ "library": "AlifdProLayout",
+ "urls": [
+ "https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/dist/AlifdProLayout.js",
+ "https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/dist/AlifdProLayout.css"
+ ],
+ "editUrls": [
+ "https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/view.js",
+ "https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/view.css"
+ ]
+ },
+ {
+ "package": "@alifd/fusion-ui",
+ "version": "1.0.5-beta.1",
+ "library": "AlifdFusionUi",
+ "urls": [
+ "https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/dist/AlifdFusionUi.js",
+ "https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/dist/AlifdFusionUi.css"
+ ],
+ "editUrls": [
+ "https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/build/lowcode/view.js",
+ "https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/build/lowcode/view.css"
+ ]
+ }
+ ],
+ "components": [
+ {
+ "exportName": "AlilcLowcodeMaterialsMeta",
+ "npm": {
+ "package": "@alilc/lowcode-materials"
+ },
+ "url": "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/build/lowcode/meta.js",
+ "urls": {
+ "default": "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/build/lowcode/meta.js",
+ "design": "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/build/lowcode/meta.design.js"
+ }
+ },
+ {
+ "exportName": "AlifdProLayoutMeta",
+ "npm": {
+ "package": "@alifd/pro-layout",
+ "version": "1.0.1-beta.5"
+ },
+ "url": "https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/meta.js",
+ "urls": {
+ "default": "https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/meta.js",
+ "design": "https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/meta.design.js"
+ }
+ },
+ {
+ "exportName": "AlifdFusionUiMeta",
+ "npm": {
+ "package": "@alifd/fusion-ui"
+ },
+ "url": "https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/build/lowcode/meta.js",
+ "urls": {
+ "default": "https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/build/lowcode/meta.js",
+ "design": "https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/build/lowcode/meta.design.js"
+ }
+ }
+ ],
+ "sort": {
+ "groupList": [
+ "精选组件",
+ "原子组件"
+ ],
+ "categoryList": [
+ "基础元素",
+ "布局容器类",
+ "表格类",
+ "表单详情类",
+ "帮助类",
+ "对话框类",
+ "业务类",
+ "通用",
+ "引导",
+ "信息输入",
+ "信息展示",
+ "信息反馈"
+ ]
+ },
+ "groupList": [
+ "精选组件",
+ "原子组件"
+ ],
+ "ignoreComponents": {}
+}
diff --git a/public/favicon.png b/public/favicon.png
new file mode 100644
index 0000000..307ffbd
Binary files /dev/null and b/public/favicon.png differ
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..3b4884a
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ 阿里低代码引擎 Demo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/mock-pages.json b/public/mock-pages.json
new file mode 100644
index 0000000..8e20f2f
--- /dev/null
+++ b/public/mock-pages.json
@@ -0,0 +1 @@
+{"success":true,"content":[{"gmtModified":"2021-03-06 00:40:54","formUuid":"FORM-6X866SC1KM4O4BLF3U7879QB0EMT2Z3TGIWLKW","parentNavUuid":"NAV-SYSTEM-PARENT-UUID","hidden":"n","navUuid":"FORM-6X866SC1KM4O4BLF3U7879QB0EMT2Z3TGIWLKW","navType":"PAGE","isIndex":"n","isNew":"n","gmtCreate":"2021-03-06 00:27:26","title":{"en_US":"页面1","zh_CN":"页面1","type":"i18n"},"relateUuid":"FORM-6X866SC1KM4O4BLF3U7879QB0EMT2Z3TGIWLKW","parentId":0,"listOrder":0,"id":556103}]}
\ No newline at end of file
diff --git a/public/mock/info.json b/public/mock/info.json
new file mode 100644
index 0000000..006209b
--- /dev/null
+++ b/public/mock/info.json
@@ -0,0 +1,3 @@
+{
+ "info": "Hello AliLowCode!!"
+}
\ No newline at end of file
diff --git a/public/preview.html b/public/preview.html
new file mode 100644
index 0000000..798b156
--- /dev/null
+++ b/public/preview.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+ 预览低代码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/schema.json b/public/schema.json
new file mode 100644
index 0000000..4d95a15
--- /dev/null
+++ b/public/schema.json
@@ -0,0 +1,291 @@
+{
+ "componentName": "Page",
+ "id": "node_dockcviv8fo1",
+ "props": {
+ "ref": "outerView",
+ "style": {
+ "height": "100%"
+ }
+ },
+ "fileName": "/",
+ "dataSource": {
+ "list": [
+ {
+ "type": "fetch",
+ "isInit": true,
+ "options": {
+ "params": {},
+ "method": "GET",
+ "isCors": true,
+ "timeout": 5000,
+ "headers": {},
+ "uri": "mock/info.json"
+ },
+ "id": "info"
+ }
+ ]
+ },
+ "state": {
+ "text": {
+ "type": "JSExpression",
+ "value": "\"outer\""
+ },
+ "isShowDialog": {
+ "type": "JSExpression",
+ "value": "false"
+ }
+ },
+ "css": "body {\n font-size: 12px;\n}\n\n.button {\n width: 100px;\n color: #ff00ff\n}",
+ "lifeCycles": {
+ "componentDidMount": {
+ "type": "JSFunction",
+ "value": "function componentDidMount() {\n console.log('did mount');\n}"
+ },
+ "componentWillUnmount": {
+ "type": "JSFunction",
+ "value": "function componentWillUnmount() {\n console.log('will unmount');\n}"
+ }
+ },
+ "methods": {
+ "testFunc": {
+ "type": "JSFunction",
+ "value": "function testFunc() {\n console.log('test func');\n}"
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function onClick() {\n this.setState({\n isShowDialog: true\n });\n}"
+ },
+ "closeDialog": {
+ "type": "JSFunction",
+ "value": "function closeDialog() {\n this.setState({\n isShowDialog: false\n });\n}"
+ }
+ },
+ "originCode": "class LowcodeComponent extends Component {\n state = {\n \"text\": \"outer\",\n \"isShowDialog\": false\n }\n componentDidMount() {\n console.log('did mount');\n }\n componentWillUnmount() {\n console.log('will unmount');\n }\n testFunc() {\n console.log('test func');\n }\n onClick() {\n this.setState({\n isShowDialog: true\n })\n }\n closeDialog() {\n this.setState({\n isShowDialog: false\n })\n }\n}",
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextPage",
+ "id": "node_ockzs2vw431",
+ "props": {
+ "headerDivider": true,
+ "minHeight": "100vh",
+ "presetNav": true,
+ "presetAside": true,
+ "footer": false,
+ "nav": false,
+ "aside": false,
+ "placeholderStyle": {
+ "gridRowEnd": "span 1",
+ "gridColumnEnd": "span 12"
+ },
+ "headerProps": {
+ "background": "surface"
+ },
+ "header": {
+ "type": "JSSlot",
+ "value": [
+ {
+ "componentName": "NextPageHeader",
+ "id": "node_ockzs2vw433",
+ "props": {},
+ "title": "页面头部",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextRowColContainer",
+ "id": "node_ockzs2vw434",
+ "props": {
+ "rowGap": 20,
+ "colGap": 20
+ },
+ "title": "行列容器",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextRow",
+ "id": "node_ockzs2vw435",
+ "props": {},
+ "title": "行",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextCol",
+ "id": "node_ockzs2vw436",
+ "props": {
+ "colSpan": 1
+ },
+ "title": "列",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextP",
+ "id": "node_ockzvfoetv17",
+ "props": {
+ "wrap": false,
+ "type": "body2",
+ "verAlign": "middle",
+ "textSpacing": true,
+ "align": "left"
+ },
+ "docId": "dockzvfoetv",
+ "title": "段落",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextText",
+ "id": "node_ockzvfoetv18",
+ "props": {
+ "type": "h5",
+ "children": {
+ "type": "JSExpression",
+ "value": "this.state.info.info",
+ "mock": "标题标题"
+ },
+ "mark": false,
+ "code": false,
+ "delete": false,
+ "underline": false,
+ "strong": false
+ },
+ "docId": "dockzvfoetv",
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "title": "header"
+ },
+ "isTab": false,
+ "contentAlignCenter": false,
+ "contentProps": {
+ "style": {
+ "background": "rgba(255,255,255,0)"
+ }
+ }
+ },
+ "title": "页面",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextBlock",
+ "id": "node_ockzs2vw437",
+ "props": {
+ "placeholderStyle": {
+ "height": "100%"
+ },
+ "noPadding": false,
+ "noBorder": false,
+ "title": "区域标题",
+ "rowGap": 20,
+ "colGap": 20,
+ "background": "surface",
+ "layoutmode": "O",
+ "strict": true,
+ "colSpan": 12,
+ "rowSpan": 1,
+ "mode": "transparent",
+ "childTotalColumns": 12
+ },
+ "title": "区域",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextBlockCell",
+ "id": "node_ockzs2vw438",
+ "props": {
+ "colSpan": 12,
+ "rowSpan": 1,
+ "mode": "procard",
+ "isAutoContainer": true,
+ "title": "区块标题"
+ },
+ "hidden": false,
+ "title": "",
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextRowColContainer",
+ "id": "node_ockzs2vw439",
+ "props": {
+ "rowGap": 20,
+ "colGap": 20
+ },
+ "title": "行列容器",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextRow",
+ "id": "node_ockzs2vw43a",
+ "props": {},
+ "title": "行",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": "",
+ "children": [
+ {
+ "componentName": "NextCol",
+ "id": "node_ockzs2vw43b",
+ "props": {
+ "colSpan": 1
+ },
+ "title": "列",
+ "hidden": false,
+ "isLocked": false,
+ "condition": true,
+ "conditionGroup": ""
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/scripts/watchdog.js b/scripts/watchdog.js
new file mode 100755
index 0000000..57964a5
--- /dev/null
+++ b/scripts/watchdog.js
@@ -0,0 +1,15 @@
+#!/usr/bin/env node
+const fs = require('fs');
+const { join } = require('path');
+
+const workingDir = process.cwd();
+
+const pkg = JSON.parse(fs.readFileSync(join(workingDir, 'package.json'), 'utf-8'));
+if (pkg.private) return;
+const { files } = pkg;
+files.forEach(file => {
+ const fileDir = join(workingDir, file);
+ if (!fs.existsSync(fileDir)) {
+ throw new Error(`${fileDir} does not exist, plz run build`);
+ }
+});
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..1ee60d1
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,35 @@
+import { init } from '@alilc/lowcode-engine';
+import registerPlugins from './universal/plugin';
+import './universal/global.scss';
+
+const preference = new Map();
+preference.set('DataSourcePane', {
+ importPlugins: [],
+ dataSourceTypes: [
+ {
+ type: 'fetch',
+ },
+ {
+ type: 'jsonp',
+ }
+ ]
+});
+
+(async function main() {
+ await registerPlugins();
+
+ init(document.getElementById('lce-container')!, {
+ // designMode: 'live',
+ // locale: 'zh-CN',
+ enableCondition: true,
+ enableCanvasLock: true,
+ // 默认绑定变量
+ supportVariableGlobally: true,
+ // simulatorUrl 在当 engine-core.js 同一个路径下时是不需要配置的!!!
+ // 这里因为用的是 unpkg,在不同 npm 包,engine-core.js 和 react-simulator-renderer.js 是不同路径
+ simulatorUrl: [
+ 'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@beta/dist/css/react-simulator-renderer.css',
+ 'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@beta/dist/js/react-simulator-renderer.js'
+ ]
+ }, preference);
+})();
diff --git a/src/preview.tsx b/src/preview.tsx
new file mode 100644
index 0000000..27627ff
--- /dev/null
+++ b/src/preview.tsx
@@ -0,0 +1,63 @@
+import ReactDOM from 'react-dom';
+import React, { useState } from 'react';
+import { Loading } from '@alifd/next';
+import { buildComponents, assetBundle, AssetLevel, AssetLoader } from '@alilc/lowcode-utils';
+import ReactRenderer from '@alilc/lowcode-react-renderer';
+import { injectComponents } from '@alilc/lowcode-plugin-inject';
+
+const SamplePreview = () => {
+ const [data, setData] = useState({});
+
+ async function init() {
+ const packages = JSON.parse(window.localStorage.getItem('packages') || '');
+ const projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || '');
+ const { componentsMap: componentsMapArray, componentsTree } = projectSchema;
+ const componentsMap: any = {};
+ componentsMapArray.forEach((component: any) => {
+ componentsMap[component.componentName] = component;
+ });
+ const schema = componentsTree[0];
+
+ const libraryMap = {};
+ const libraryAsset = [];
+ packages.forEach(({ package: _package, library, urls, renderUrls }) => {
+ libraryMap[_package] = library;
+ if (renderUrls) {
+ libraryAsset.push(renderUrls);
+ } else if (urls) {
+ libraryAsset.push(urls);
+ }
+ });
+
+ const vendors = [assetBundle(libraryAsset, AssetLevel.Library)];
+
+ // TODO asset may cause pollution
+ const assetLoader = new AssetLoader();
+ await assetLoader.load(libraryAsset);
+ const components = await injectComponents(buildComponents(libraryMap, componentsMap));
+
+ setData({
+ schema,
+ components,
+ });
+ }
+
+ const { schema, components } = data;
+
+ if (!schema || !components) {
+ init();
+ return ;
+ }
+
+ return (
+
+
+
+ );
+};
+
+ReactDOM.render(, document.getElementById('ice-container'));
diff --git a/src/sample-plugins/logo/index.scss b/src/sample-plugins/logo/index.scss
new file mode 100644
index 0000000..3140ac3
--- /dev/null
+++ b/src/sample-plugins/logo/index.scss
@@ -0,0 +1,11 @@
+.lowcode-plugin-logo {
+ .logo {
+ display: block;
+ width: 139px;
+ height: 26px;
+ cursor: pointer;
+ background-size: contain;
+ background-position: center;
+ background-repeat: no-repeat;
+ }
+}
diff --git a/src/sample-plugins/logo/index.tsx b/src/sample-plugins/logo/index.tsx
new file mode 100644
index 0000000..ff4bbe2
--- /dev/null
+++ b/src/sample-plugins/logo/index.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import './index.scss';
+import { PluginProps } from '@alilc/lowcode-types';
+
+export interface IProps {
+ logo?: string;
+ href?: string;
+}
+
+const Logo: React.FC = (props): React.ReactElement => {
+ return (
+
+ );
+};
+
+export default Logo;
diff --git a/src/setters/behavior-setter.tsx b/src/setters/behavior-setter.tsx
new file mode 100644
index 0000000..34e9be5
--- /dev/null
+++ b/src/setters/behavior-setter.tsx
@@ -0,0 +1,27 @@
+import * as React from 'react';
+import BehaviorSetter from '@alilc/lowcode-setter-behavior';
+
+
+const defaultExtraBehaviorActions: any[] = [];
+class LocalBehaviorSetter extends React.Component {
+ render() {
+ // ignore url && responseFormatter props, use default ones
+ const { url: propsUrl, responseFormatter: propsFormatter, extraBehaviorActions: propsExtraBehaviorActions = [], ...otherProps } = this.props;
+ const url = 'https://hn.algolia.com/api/v1/search?query';
+ const responseFormatter = (response) => response.hits.map((item) => ({
+ label: item.title,
+ value: item.author
+ }));
+ const extraBehaviorActions = propsExtraBehaviorActions.concat(defaultExtraBehaviorActions);
+ return (
+
+ );
+ }
+}
+
+export default LocalBehaviorSetter;
\ No newline at end of file
diff --git a/src/setters/custom-setter.tsx b/src/setters/custom-setter.tsx
new file mode 100644
index 0000000..0383473
--- /dev/null
+++ b/src/setters/custom-setter.tsx
@@ -0,0 +1,12 @@
+import React, { Component } from 'react'; // import classNames from 'classnames';
+
+class CustomSetter extends Component {
+ render() {
+ const { defaultValue, value, onChange } = this.props;
+ const { editor } = this.props.field;
+
+ return hello world
;
+ }
+}
+
+export default CustomSetter;
diff --git a/src/universal/global.scss b/src/universal/global.scss
new file mode 100644
index 0000000..02906a3
--- /dev/null
+++ b/src/universal/global.scss
@@ -0,0 +1,55 @@
+body {
+ font-family: PingFangSC-Regular, Roboto, Helvetica Neue, Helvetica, Tahoma, Arial, PingFang SC-Light, Microsoft YaHei;
+ font-size: 12px;
+ * {
+ box-sizing: border-box;
+ }
+}
+
+body, #lce-container {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ box-sizing: border-box;
+ padding: 0;
+ margin: 0;
+ overflow: hidden;
+ text-rendering: optimizeLegibility;
+ -webkit-user-select: none;
+ -webkit-user-drag: none;
+ -webkit-text-size-adjust: none;
+ -webkit-touch-callout: none;
+ -webkit-font-smoothing: antialiased;
+ #engine {
+ width: 100%;
+ height: 100%;
+ }
+}
+
+html {
+ min-width: 1024px;
+}
+
+.save-sample {
+ width: 80px;
+ height: 30px;
+ background-color: #5584FF;
+ border: none;
+ outline: none;
+ border-radius: 4px;
+ color: white;
+ cursor: pointer;
+}
+
+.load-assets {
+ width: 100px;
+ height: 30px;
+ background-color: #5584FF;
+ border: none;
+ outline: none;
+ border-radius: 4px;
+ color: white;
+ cursor: pointer;
+}
diff --git a/src/universal/plugin.tsx b/src/universal/plugin.tsx
new file mode 100644
index 0000000..12e7d9f
--- /dev/null
+++ b/src/universal/plugin.tsx
@@ -0,0 +1,272 @@
+import React from 'react';
+import {
+ ILowCodePluginContext,
+ plugins,
+ skeleton,
+ project,
+ setters,
+} from '@alilc/lowcode-engine';
+import { Button } from '@alifd/next';
+import UndoRedoPlugin from '@alilc/lowcode-plugin-undo-redo';
+import ComponentsPane from '@alilc/lowcode-plugin-components-pane';
+import ZhEnPlugin from '@alilc/lowcode-plugin-zh-en';
+import CodeGenPlugin from '@alilc/lowcode-plugin-code-generator';
+import DataSourcePanePlugin from '@alilc/lowcode-plugin-datasource-pane';
+import SchemaPlugin from '@alilc/lowcode-plugin-schema';
+import CodeEditor from "@alilc/lowcode-plugin-code-editor";
+import ManualPlugin from "@alilc/lowcode-plugin-manual";
+import Inject, { injectAssets } from '@alilc/lowcode-plugin-inject';
+import SimulatorResizer from '@alilc/lowcode-plugin-simulator-select';
+
+// 注册到引擎
+import TitleSetter from '@alilc/lowcode-setter-title';
+import BehaviorSetter from '../setters/behavior-setter';
+import CustomSetter from '../setters/custom-setter';
+import Logo from '../sample-plugins/logo';
+
+import {
+ loadIncrementalAssets,
+ getPageSchema,
+ saveSchema,
+ resetSchema,
+ preview,
+} from './utils';
+import assets from '../../public/assets.json'
+
+export default async function registerPlugins() {
+ await plugins.register(ManualPlugin);
+
+ await plugins.register(Inject);
+
+ // plugin API 见 https://yuque.antfin.com/ali-lowcode/docs/cdukce
+ SchemaPlugin.pluginName = 'SchemaPlugin';
+ await plugins.register(SchemaPlugin);
+
+ SimulatorResizer.pluginName = 'SimulatorResizer';
+ plugins.register(SimulatorResizer);
+
+ const editorInit = (ctx: ILowCodePluginContext) => {
+ return {
+ name: 'editor-init',
+ async init() {
+ // 修改面包屑组件的分隔符属性setter
+ // const assets = await (
+ // await fetch(
+ // `https://alifd.alicdn.com/npm/@alilc/lowcode-materials/build/lowcode/assets-prod.json`
+ // )
+ // ).json();
+ // 设置物料描述
+ const { material, project } = ctx;
+
+ material.setAssets(await injectAssets(assets));
+
+ const schema = await getPageSchema();
+
+ // 加载 schema
+ project.openDocument(schema);
+ },
+ };
+ }
+ editorInit.pluginName = 'editorInit';
+ await plugins.register(editorInit);
+
+ const builtinPluginRegistry = (ctx: ILowCodePluginContext) => {
+ return {
+ name: 'builtin-plugin-registry',
+ async init() {
+ const { skeleton } = ctx;
+ // 注册 logo 面板
+ skeleton.add({
+ area: 'topArea',
+ type: 'Widget',
+ name: 'logo',
+ content: Logo,
+ contentProps: {
+ logo: 'https://img.alicdn.com/imgextra/i4/O1CN013w2bmQ25WAIha4Hx9_!!6000000007533-55-tps-137-26.svg',
+ href: '/',
+ },
+ props: {
+ align: 'left',
+ },
+ });
+
+ // 注册组件面板
+ const componentsPane = skeleton.add({
+ area: 'leftArea',
+ type: 'PanelDock',
+ name: 'componentsPane',
+ content: ComponentsPane,
+ contentProps: {},
+ props: {
+ align: 'top',
+ icon: 'zujianku',
+ description: '组件库',
+ },
+ });
+ componentsPane?.disable?.();
+ project.onSimulatorRendererReady(() => {
+ componentsPane?.enable?.();
+ })
+ },
+ };
+ }
+ builtinPluginRegistry.pluginName = 'builtinPluginRegistry';
+ await plugins.register(builtinPluginRegistry);
+
+ // 设置内置 setter 和事件绑定、插件绑定面板
+ const setterRegistry = (ctx: ILowCodePluginContext) => {
+ const { setterMap, pluginMap } = window.AliLowCodeEngineExt;
+ return {
+ name: 'ext-setters-registry',
+ async init() {
+ const { setters, skeleton } = ctx;
+ // 注册setterMap
+ setters.registerSetter(setterMap);
+ // 注册插件
+ // 注册事件绑定面板
+ skeleton.add({
+ area: 'centerArea',
+ type: 'Widget',
+ content: pluginMap.EventBindDialog,
+ name: 'eventBindDialog',
+ props: {},
+ });
+
+ // 注册变量绑定面板
+ skeleton.add({
+ area: 'centerArea',
+ type: 'Widget',
+ content: pluginMap.VariableBindDialog,
+ name: 'variableBindDialog',
+ props: {},
+ });
+ },
+ };
+ }
+ setterRegistry.pluginName = 'setterRegistry';
+ await plugins.register(setterRegistry);
+
+ // 注册回退/前进
+ await plugins.register(UndoRedoPlugin);
+
+ // 注册中英文切换
+ await plugins.register(ZhEnPlugin);
+
+ const loadAssetsSample = (ctx: ILowCodePluginContext) => {
+ return {
+ name: 'loadAssetsSample',
+ async init() {
+ const { skeleton } = ctx;
+
+ skeleton.add({
+ name: 'loadAssetsSample',
+ area: 'topArea',
+ type: 'Widget',
+ props: {
+ align: 'right',
+ width: 80,
+ },
+ content: (
+
+ ),
+ });
+ },
+ };
+ };
+ loadAssetsSample.pluginName = 'loadAssetsSample';
+ await plugins.register(loadAssetsSample);
+
+ // 注册保存面板
+ const saveSample = (ctx: ILowCodePluginContext) => {
+ return {
+ name: 'saveSample',
+ async init() {
+ const { skeleton, hotkey } = ctx;
+
+ skeleton.add({
+ name: 'saveSample',
+ area: 'topArea',
+ type: 'Widget',
+ props: {
+ align: 'right',
+ },
+ content: (
+
+ ),
+ });
+ skeleton.add({
+ name: 'resetSchema',
+ area: 'topArea',
+ type: 'Widget',
+ props: {
+ align: 'right',
+ },
+ content: (
+
+ ),
+ });
+ hotkey.bind('command+s', (e) => {
+ e.preventDefault();
+ saveSchema();
+ });
+ },
+ };
+ }
+ saveSample.pluginName = 'saveSample';
+ await plugins.register(saveSample);
+
+ DataSourcePanePlugin.pluginName = 'DataSourcePane';
+ await plugins.register(DataSourcePanePlugin);
+
+ CodeEditor.pluginName = 'CodeEditor';
+ await plugins.register(CodeEditor);
+
+ // 注册出码插件
+ CodeGenPlugin.pluginName = 'CodeGenPlugin';
+ await plugins.register(CodeGenPlugin);
+
+ const previewSample = (ctx: ILowCodePluginContext) => {
+ return {
+ name: 'previewSample',
+ async init() {
+ const { skeleton } = ctx;
+ skeleton.add({
+ name: 'previewSample',
+ area: 'topArea',
+ type: 'Widget',
+ props: {
+ align: 'right',
+ },
+ content: (
+
+ ),
+ });
+ },
+ };
+ };
+ previewSample.pluginName = 'previewSample';
+ await plugins.register(previewSample);
+
+ const customSetter = (ctx: ILowCodePluginContext) => {
+ return {
+ name: '___registerCustomSetter___',
+ async init() {
+ const { setters } = ctx;
+
+ setters.registerSetter('TitleSetter', TitleSetter);
+ setters.registerSetter('BehaviorSetter', BehaviorSetter);
+ setters.registerSetter('CustomSetter', CustomSetter);
+ },
+ };
+ }
+ customSetter.pluginName = 'customSetter';
+ await plugins.register(customSetter);
+};
diff --git a/src/universal/utils.ts b/src/universal/utils.ts
new file mode 100644
index 0000000..9baf0f8
--- /dev/null
+++ b/src/universal/utils.ts
@@ -0,0 +1,298 @@
+import { material, project } from '@alilc/lowcode-engine';
+import { filterPackages } from '@alilc/lowcode-plugin-inject'
+import { Message, Dialog } from '@alifd/next';
+
+export const loadIncrementalAssets = () => {
+ material?.onChangeAssets(() => {
+ Message.success('[MCBreadcrumb] 物料加载成功');
+ });
+
+ material.loadIncrementalAssets({
+ packages: [
+ {
+ title: 'MCBreadcrumb',
+ package: 'mc-breadcrumb',
+ version: '1.0.0',
+ urls: [
+ 'https://unpkg.alibaba-inc.com/mc-breadcrumb@1.0.0/dist/MCBreadcrumb.js',
+ 'https://unpkg.alibaba-inc.com/mc-breadcrumb@1.0.0/dist/MCBreadcrumb.css',
+ ],
+ library: 'MCBreadcrumb',
+ },
+ ],
+ components: [
+ {
+ componentName: 'MCBreadcrumb',
+ title: 'MCBreadcrumb',
+ docUrl: '',
+ screenshot: '',
+ npm: {
+ package: 'mc-breadcrumb',
+ version: '1.0.0',
+ exportName: 'MCBreadcrumb',
+ main: 'lib/index.js',
+ destructuring: false,
+ subName: '',
+ },
+ props: [
+ {
+ name: 'prefix',
+ propType: 'string',
+ description: '样式类名的品牌前缀',
+ defaultValue: 'next-',
+ },
+ {
+ name: 'title',
+ propType: 'string',
+ description: '标题',
+ defaultValue: 'next-',
+ },
+ {
+ name: 'rtl',
+ propType: 'bool',
+ },
+ {
+ name: 'children',
+ propType: {
+ type: 'instanceOf',
+ value: 'node',
+ },
+ description: '面包屑子节点,需传入 Breadcrumb.Item',
+ },
+ {
+ name: 'maxNode',
+ propType: {
+ type: 'oneOfType',
+ value: [
+ 'number',
+ {
+ type: 'oneOf',
+ value: ['auto'],
+ },
+ ],
+ },
+ description:
+ '面包屑最多显示个数,超出部分会被隐藏, 设置为 auto 会自动根据父元素的宽度适配。',
+ defaultValue: 100,
+ },
+ {
+ name: 'separator',
+ propType: {
+ type: 'instanceOf',
+ value: 'node',
+ },
+ description: '分隔符,可以是文本或 Icon',
+ },
+ {
+ name: 'component',
+ propType: {
+ type: 'oneOfType',
+ value: ['string', 'func'],
+ },
+ description: '设置标签类型',
+ defaultValue: 'nav',
+ },
+ {
+ name: 'className',
+ propType: 'any',
+ },
+ {
+ name: 'style',
+ propType: 'object',
+ },
+ ],
+ configure: {
+ component: {
+ isContainer: true,
+ isModel: true,
+ rootSelector: 'div.MCBreadcrumb',
+ },
+ },
+ },
+ ],
+
+ componentList: [
+ {
+ title: '常用',
+ icon: '',
+ children: [
+ {
+ componentName: 'MCBreadcrumb',
+ title: 'MC面包屑',
+ icon: '',
+ package: 'mc-breadcrumb',
+ library: 'MCBreadcrumb',
+ snippets: [
+ {
+ title: 'MC面包屑',
+ screenshot:
+ 'https://alifd.oss-cn-hangzhou.aliyuncs.com/fusion-cool/icons/icon-light/ic_light_breadcrumb.png',
+ schema: {
+ componentName: 'MCBreadcrumb',
+ props: {
+ title: '物料中心',
+ prefix: 'next-',
+ maxNode: 100,
+ },
+ },
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ });
+};
+
+export const preview = () => {
+ saveSchema();
+ setTimeout(() => {
+ window.open(`./preview.html${location.search}`);
+ }, 500);
+};
+
+export const saveSchema = async () => {
+ window.localStorage.setItem(
+ 'projectSchema',
+ JSON.stringify(project.exportSchema())
+ );
+ const packages = await filterPackages(material.getAssets().packages);
+ window.localStorage.setItem(
+ 'packages',
+ JSON.stringify(packages)
+ );
+ Message.success('成功保存到本地');
+};
+
+export const resetSchema = async () => {
+ try {
+ await new Promise((resolve, reject) => {
+ Dialog.confirm({
+ content: '确定要重置吗?您所有的修改都将消失!',
+ onOk: () => {
+ resolve();
+ },
+ onCancel: () => {
+ reject()
+ },
+ })
+ })
+ } catch(err) {
+ return
+ }
+
+ let schema
+ try {
+ schema = await request('./schema.json')
+ } catch(err) {
+ schema = {
+ componentName: 'Page',
+ fileName: 'sample',
+ }
+ }
+
+ window.localStorage.setItem(
+ 'projectSchema',
+ JSON.stringify({
+ componentsTree: [schema],
+ componentsMap: material.componentsMap,
+ version: '1.0.0',
+ i18n: {},
+ })
+ );
+
+ project.getCurrentDocument()?.importSchema(schema);
+ project.simulatorHost?.rerender();
+ Message.success('成功重置页面');
+}
+
+export const getPageSchema = async () => {
+ const schema = JSON.parse(
+ window.localStorage.getItem('projectSchema') || '{}'
+ );
+
+ const pageSchema = schema?.componentsTree?.[0];
+
+ if (pageSchema) {
+ return pageSchema;
+ }
+ return await request('./schema.json');
+};
+
+function request(
+ dataAPI: string,
+ method = 'GET',
+ data?: object | string,
+ headers?: object,
+ otherProps?: any,
+): Promise {
+ return new Promise((resolve, reject): void => {
+ if (otherProps && otherProps.timeout) {
+ setTimeout((): void => {
+ reject(new Error('timeout'));
+ }, otherProps.timeout);
+ }
+ fetch(dataAPI, {
+ method,
+ credentials: 'include',
+ headers,
+ body: data,
+ ...otherProps,
+ })
+ .then((response: Response): any => {
+ switch (response.status) {
+ case 200:
+ case 201:
+ case 202:
+ return response.json();
+ case 204:
+ if (method === 'DELETE') {
+ return {
+ success: true,
+ };
+ } else {
+ return {
+ __success: false,
+ code: response.status,
+ };
+ }
+ case 400:
+ case 401:
+ case 403:
+ case 404:
+ case 406:
+ case 410:
+ case 422:
+ case 500:
+ return response
+ .json()
+ .then((res: object): any => {
+ return {
+ __success: false,
+ code: response.status,
+ data: res,
+ };
+ })
+ .catch((): object => {
+ return {
+ __success: false,
+ code: response.status,
+ };
+ });
+ default:
+ return null;
+ }
+ })
+ .then((json: any): void => {
+ if (json && json.__success !== false) {
+ resolve(json);
+ } else {
+ delete json.__success;
+ reject(json);
+ }
+ })
+ .catch((err: Error): void => {
+ reject(err);
+ });
+ });
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..23314ab
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,44 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "declaration": true,
+ "lib": ["es2015", "dom"],
+ // Target latest version of ECMAScript.
+ "target": "esnext",
+ // Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
+ "module": "esnext",
+ // Search under node_modules for non-relative imports.
+ "moduleResolution": "node",
+ // Process & infer types from .js files.
+ "allowJs": true,
+ // Report errors in .js files.
+ "checkJs": false,
+ // Don't emit; allow Babel to transform files.
+ // "noEmit": true,
+ // Enable strictest settings like strictNullChecks & noImplicitAny.
+ "strict": true,
+ // Allow default imports from modules with no default export. This does not affect code emit, just typechecking.
+ "allowSyntheticDefaultImports": true,
+ // Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.
+ "esModuleInterop": true,
+ // Specify JSX code generation: 'preserve', 'react-native', or 'react'.
+ "jsx": "preserve",
+ // Import emit helpers (e.g. __extends, __rest, etc..) from tslib
+ "importHelpers": true,
+ // Enables experimental support for ES7 decorators.
+ "experimentalDecorators": true,
+ // Generates corresponding .map file.
+ "sourceMap": true,
+ // Disallow inconsistently-cased references to the same file.
+ "forceConsistentCasingInFileNames": true,
+ // Allow json import
+ "resolveJsonModule": true,
+ // skip type checking of declaration files
+ "skipLibCheck": true,
+ "outDir": "lib"
+ },
+ "include": [
+ "./src/"
+ ],
+ "exclude": ["**/test", "**/lib", "**/es", "node_modules"]
+}