feat: first commit - genesis

This commit is contained in:
LeoYuan 袁力皓 2022-02-22 09:40:57 +08:00
parent 4323728db3
commit 6a26531007
24 changed files with 1602 additions and 0 deletions

95
.gitignore vendored Normal file
View File

@ -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

7
.prettierrc.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
printWidth: 100,
tabWidth: 2,
semi: true,
singleQuote: true,
trailingComma: 'all',
};

9
README.md Normal file
View File

@ -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)

38
build.json Normal file
View File

@ -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"
]
}

58
build.plugin.js Normal file
View File

@ -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');
});
};

45
package.json Normal file
View File

@ -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"
}
}

139
public/assets.json Normal file
View File

@ -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": {}
}

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

41
public/index.html Normal file
View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>阿里低代码引擎 Demo</title>
<link rel="icon" href="http://lowcode-engine.cn/public/favicon.svg">
<link href="./css/index.css" rel="stylesheet" />
<!-- 低代码引擎的页面主题样式,可以替换为 theme-lowcode-dark -->
<link href="https://alifd.alicdn.com/npm/@alifd/theme-lowcode-light@0.2.1/variables.css" rel="stylesheet" />
<link href="https://alifd.alicdn.com/npm/@alifd/theme-lowcode-light@0.2.1/dist/next.var.min.css" rel="stylesheet" />
<!-- 低代码引擎的页面框架样式 -->
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alilc/lowcode-engine@1.0.1/dist/css/engine-core.css" />
<!-- 低代码引擎官方扩展的样式 -->
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alilc/lowcode-engine-ext@1.0.2/dist/css/engine-ext.css" />
<!-- React可替换为 production 包 -->
<script src="https://g.alicdn.com/code/lib/react/16.13.1/umd/react.production.min.js"></script>
<!-- React DOM可替换为 production 包 -->
<script src="https://g.alicdn.com/code/lib/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<!-- React 向下兼容,预防物料层的依赖 -->
<script src="https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js"></script>
<script src="https://g.alicdn.com/platform/c/react15-polyfill/0.0.1/dist/index.js"></script>
<!-- lodash低代码编辑器的依赖 -->
<script src="https://g.alicdn.com/platform/c/lodash/4.6.1/lodash.min.js"></script>
<!-- 日期处理包Fusion Next 的依赖 -->
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
<!-- Fusion Next 的主包,低代码编辑器的依赖 -->
<script src="https://g.alicdn.com/code/lib/alifd__next/1.23.24/next.min.js"></script>
<!-- 低代码引擎的主包 -->
<script crossorigin="anonymous" src="https://alifd.alicdn.com/npm/@alilc/lowcode-engine@1.0.1/dist/js/engine-core.js"></script>
<!-- 低代码引擎官方扩展的主包 -->
<script crossorigin="anonymous" src="https://alifd.alicdn.com/npm/@alilc/lowcode-engine-ext@1.0.2/dist/js/engine-ext.js"></script>
</head>
<body>
<div id="lce-container"></div>
<script type="text/javascript" src="./js/index.js"></script>
</body>
</html>

1
public/mock-pages.json Normal file
View File

@ -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}]}

3
public/mock/info.json Normal file
View File

@ -0,0 +1,3 @@
{
"info": "Hello AliLowCode!!"
}

25
public/preview.html Normal file
View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>预览低代码</title>
<link href="https://g.alicdn.com/code/lib/alifd__next/1.23.24/next.min.css" rel="stylesheet">
<link href="./css/preview.css" rel="stylesheet">
</head>
<body>
<div id="ice-container"></div>
<script>
window.g_config = {
locale: 'zh_CN',
};
</script>
<script src="https://g.alicdn.com/code/lib/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://g.alicdn.com/code/lib/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js"></script>
<script src="https://g.alicdn.com/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js"></script>
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
<script src="https://g.alicdn.com/code/lib/alifd__next/1.23.24/next.min.js"></script>
<script type="text/javascript" src="./js/preview.js"></script>
</body>
</html>

291
public/schema.json Normal file
View File

@ -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": ""
}
]
}
]
}
]
}
]
}
]
}
]
}

15
scripts/watchdog.js Executable file
View File

@ -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`);
}
});

35
src/index.ts Normal file
View File

@ -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);
})();

63
src/preview.tsx Normal file
View File

@ -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 <Loading fullScreen />;
}
return (
<div className="lowcode-plugin-sample-preview">
<ReactRenderer
className="lowcode-plugin-sample-preview-content"
schema={schema}
components={components}
/>
</div>
);
};
ReactDOM.render(<SamplePreview />, document.getElementById('ice-container'));

View File

@ -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;
}
}

View File

@ -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<IProps & PluginProps> = (props): React.ReactElement => {
return (
<div className="lowcode-plugin-logo">
<a className="logo" target="blank" href={props.href || '/'} style={{ backgroundImage: `url(${props.logo})` }} />
</div>
);
};
export default Logo;

View File

@ -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 (
<BehaviorSetter
{...otherProps}
url={url}
responseFormatter={responseFormatter}
extraBehaviorActions={extraBehaviorActions}
/>
);
}
}
export default LocalBehaviorSetter;

View File

@ -0,0 +1,12 @@
import React, { Component } from 'react'; // import classNames from 'classnames';
class CustomSetter extends Component<any, any> {
render() {
const { defaultValue, value, onChange } = this.props;
const { editor } = this.props.field;
return <div>hello world</div>;
}
}
export default CustomSetter;

55
src/universal/global.scss Normal file
View File

@ -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;
}

272
src/universal/plugin.tsx Normal file
View File

@ -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: (
<Button onClick={loadIncrementalAssets}>
</Button>
),
});
},
};
};
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: (
<Button onClick={saveSchema}>
</Button>
),
});
skeleton.add({
name: 'resetSchema',
area: 'topArea',
type: 'Widget',
props: {
align: 'right',
},
content: (
<Button onClick={resetSchema}>
</Button>
),
});
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: (
<Button type="primary" onClick={preview}>
</Button>
),
});
},
};
};
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);
};

298
src/universal/utils.ts Normal file
View File

@ -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<void>((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<any> {
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);
});
});
}

44
tsconfig.json Normal file
View File

@ -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"]
}