mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-04-20 04:18:05 +00:00
Merge commit '8cbdd383cef4c9631db3e851a8a1b474392e262e' into feat/code-generator
* commit '8cbdd383cef4c9631db3e851a8a1b474392e262e': (95 commits)
chore: fix addowner
Publish
refactor: move icons to local
comment
fix: [material-parser]fix bug of main field & remove useless debugger
feat: support localizing
refactor: runtime
fix: fix bug of build errors
fix: fix bug of missing types in material-parser
feat: 🎸 support parsing fusion source code
chore: @ali/lowcode-runtime@0.8.5
feat: style setter 国际化
refactor: runtime
Publish
chore: output sourceMap
fix(settings-pane): overflow problem
feat(designer): add builtin hotkeys
fix(designer): fix insertion style
feat: add favicon for preview
feat(designer): add blank page logic
...
This commit is contained in:
commit
abc602b4a1
@ -4,3 +4,4 @@ build/
|
|||||||
.*
|
.*
|
||||||
~*
|
~*
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
3
.eslintrc
Normal file
3
.eslintrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/@ali/lowcode-config/.eslintrc"
|
||||||
|
}
|
||||||
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,3 +1,19 @@
|
|||||||
|
# project custom
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
packages/*/lib/
|
||||||
|
packages/*/es/
|
||||||
|
packages/*/dist/
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
deploy-space/packages
|
||||||
|
deploy-space/.env
|
||||||
|
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
*.log
|
*.log
|
||||||
|
|||||||
@ -2,5 +2,7 @@
|
|||||||
"trailingComma": "all",
|
"trailingComma": "all",
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true
|
"singleQuote": true,
|
||||||
|
"printWidth": 120,
|
||||||
|
"arrowParens": "always"
|
||||||
}
|
}
|
||||||
|
|||||||
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
MIT LICENSE
|
||||||
|
|
||||||
|
Copyright (c) 2020-present Alibaba Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
16
README.md
16
README.md
@ -10,21 +10,13 @@
|
|||||||
|
|
||||||
#### 跑起来:
|
#### 跑起来:
|
||||||
|
|
||||||
- `tnpm i`
|
- `npm run setup`
|
||||||
- `npm run boot`
|
- `npm start`
|
||||||
- `npm run build`
|
|
||||||
|
|
||||||
#### Link & unlink
|
#### 开发提交:
|
||||||
|
|
||||||
- `cd packages/<package-name> && tnpm link -g`
|
|
||||||
- `tnpm link @ali/<package-name>`
|
|
||||||
|
|
||||||
- `tnpm unlink @ali/<package-name>`
|
|
||||||
|
|
||||||
#### 开发过程中:
|
|
||||||
|
|
||||||
- `git add <your-files>`
|
- `git add <your-files>`
|
||||||
- `npm run commit`
|
- `npm run commit` # 在根目录
|
||||||
|
|
||||||
## 发布
|
## 发布
|
||||||
|
|
||||||
|
|||||||
11
abc.json
Normal file
11
abc.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "lowcode-engine",
|
||||||
|
"assets": {
|
||||||
|
"type": "command",
|
||||||
|
"command": {
|
||||||
|
"cmd": [
|
||||||
|
"./scripts/deploy.sh $BUILD_DEST"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
deploy-space/html/index.html
Normal file
29
deploy-space/html/index.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>LowCodeEngine Editor DEMO</title>
|
||||||
|
<link rel="shortcut icon" href="./favicon.png" />
|
||||||
|
<script src="https://g.alicdn.com/code/lib/react/16.9.0/umd/react.development.js"></script>
|
||||||
|
<script src="https://g.alicdn.com/code/lib/react-dom/16.9.0/umd/react-dom.development.js"></script>
|
||||||
|
<script src="https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js"></script>
|
||||||
|
<script> React.PropTypes = PropTypes; </script>
|
||||||
|
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css" />
|
||||||
|
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
||||||
|
<!-- lowcode engine globals -->
|
||||||
|
<link rel="stylesheet" href="./globals.css" />
|
||||||
|
<!-- lowcode engine app -->
|
||||||
|
<link rel="stylesheet" href="./lowcode-editor.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="lce-container"></div>
|
||||||
|
<!-- lowcode engine globals -->
|
||||||
|
<script src="./globals.js"></script>
|
||||||
|
<!-- lowcode engine app -->
|
||||||
|
<script src="./lowcode-editor.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
deploy-space/html/preview.html
Normal file
23
deploy-space/html/preview.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>LowCodeEngine Preview DEMO</title>
|
||||||
|
<link rel="shortcut icon" href="./favicon.png" />
|
||||||
|
<script src="https://g.alicdn.com/code/lib/react/16.9.0/umd/react.development.js"></script>
|
||||||
|
<script src="https://g.alicdn.com/code/lib/react-dom/16.9.0/umd/react-dom.development.js"></script>
|
||||||
|
<script src="https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js"></script>
|
||||||
|
<script> React.PropTypes = PropTypes; </script>
|
||||||
|
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css">
|
||||||
|
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="./lowcode-preview.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script src="./lowcode-preview.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
deploy-space/lerna.json
Normal file
9
deploy-space/lerna.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"version": "independent",
|
||||||
|
"npmClient": "yarn",
|
||||||
|
"registry": "http://registry.npm.alibaba-inc.com",
|
||||||
|
"useWorkspaces": true,
|
||||||
|
"packages": [
|
||||||
|
"packages/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
16
deploy-space/package.json
Normal file
16
deploy-space/package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"workspaces": {
|
||||||
|
"packages": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
|
"nohoist": [
|
||||||
|
"**/css-modules-typescript-loader",
|
||||||
|
"**/@alife/theme-lowcode-*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^1.11.1",
|
||||||
|
"typescript": "^3.8.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
40
deploy-space/tsconfig.json
Normal file
40
deploy-space/tsconfig.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": false,
|
||||||
|
"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": false,
|
||||||
|
// 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": false,
|
||||||
|
// 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"
|
||||||
|
},
|
||||||
|
"exclude": ["**/test", "**/lib", "**/es", "node_modules"]
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@
|
|||||||
- 使用 `camelCase` 为属性或本地变量命名
|
- 使用 `camelCase` 为属性或本地变量命名
|
||||||
- 不要为私有属性名添加 `_` 前缀
|
- 不要为私有属性名添加 `_` 前缀
|
||||||
- 尽可能使用完整的单词拼写命名
|
- 尽可能使用完整的单词拼写命名
|
||||||
- 文件夹命名统一使用小写
|
- 文件夹/文件命名统一使用小写 `get-custom-data.ts`
|
||||||
|
|
||||||
### 组件
|
### 组件
|
||||||
|
|
||||||
|
|||||||
20
lerna.json
20
lerna.json
@ -1,17 +1,27 @@
|
|||||||
{
|
{
|
||||||
"lerna": "2.11.0",
|
"lerna": "2.11.0",
|
||||||
"version": "independent",
|
"version": "independent",
|
||||||
"npmClient": "tnpm",
|
"npmClient": "tyarn",
|
||||||
|
"registry": "http://registry.npm.alibaba-inc.com",
|
||||||
|
"useWorkspaces": true,
|
||||||
|
"packages": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
"command": {
|
"command": {
|
||||||
|
"bootstrap": {
|
||||||
|
"npmClientArgs": [
|
||||||
|
"--no-package-lock"
|
||||||
|
]
|
||||||
|
},
|
||||||
"publish": {
|
"publish": {
|
||||||
|
"npmClient": "tnpm",
|
||||||
|
"verifyRegistry": false,
|
||||||
|
"verifyAccess": false,
|
||||||
"ignoreChanges": [
|
"ignoreChanges": [
|
||||||
"**/*.md",
|
"**/*.md",
|
||||||
"**/test/**"
|
"**/test/**"
|
||||||
],
|
],
|
||||||
"conventionalCommits": true
|
"conventionalCommits": true
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"packages": [
|
|
||||||
"packages/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
83
package.json
83
package.json
@ -1,53 +1,52 @@
|
|||||||
{
|
{
|
||||||
"name": "ali-lowcode-engine",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"workspaces": {
|
||||||
"boot": "lerna bootstrap --registry http://registry.npm.alibaba-inc.com --hoist",
|
"packages": [
|
||||||
"clean": "rimraf ./packages/*/lib ./packages/*/node_modules",
|
"packages/*"
|
||||||
"pub": "npm run test && lerna publish --registry http://registry.npm.alibaba-inc.com",
|
],
|
||||||
"lint": "tslint -p tsconfig.json",
|
"nohoist": [
|
||||||
"lint:fix": "tslint --fix -p tsconfig.json",
|
"**/css-modules-typescript-loader",
|
||||||
"build": "lerna run build",
|
"**/@alife/theme-lowcode-*"
|
||||||
"test": "lerna run test",
|
|
||||||
"test:snapshot": "lerna run test:snapshot",
|
|
||||||
"commit": "git-cz"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@ice/spec": "^0.1.4",
|
|
||||||
"@types/node": "^10.12.18",
|
|
||||||
"ava": "^1.0.1",
|
|
||||||
"commitizen": "^3.0.5",
|
|
||||||
"cz-conventional-changelog": "^2.1.0",
|
|
||||||
"eslint": "^6.0.1",
|
|
||||||
"git-cz": "^4.3.1",
|
|
||||||
"husky": "^1.3.1",
|
|
||||||
"lerna": "^2.11.0",
|
|
||||||
"lint-staged": "^8.1.0",
|
|
||||||
"prettier": "^1.15.3",
|
|
||||||
"rimraf": "^2.6.3",
|
|
||||||
"ts-node": "^7.0.1",
|
|
||||||
"tslint": "^6.1.0",
|
|
||||||
"tslint-config-prettier": "^1.18.0",
|
|
||||||
"typescript": "^3.2.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^8 || ^10"
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.ts": [
|
|
||||||
"prettier --write",
|
|
||||||
"tslint --fix",
|
|
||||||
"git add"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"husky": {
|
"scripts": {
|
||||||
"hooks": {
|
"build": "lerna run build --stream",
|
||||||
"pre-commit": "lint-staged"
|
"clean": "rm -rf ./packages/*/lib ./packages/*/es ./packages/*/dist ./packages/*/build",
|
||||||
}
|
"commit": "git-cz",
|
||||||
|
"pub": "lerna publish",
|
||||||
|
"setup": "./scripts/setup.sh",
|
||||||
|
"start": "./scripts/start.sh",
|
||||||
|
"test": "lerna run test --stream",
|
||||||
|
"test:snapshot": "lerna run test:snapshot"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{tsx,ts}": [
|
||||||
|
"eslint --quiet",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"commitizen": {
|
"commitizen": {
|
||||||
"path": "node_modules/cz-conventional-changelog"
|
"path": "node_modules/cz-conventional-changelog"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@ali/lowcode-config": "^2.0.5",
|
||||||
|
"ava": "^1.0.1",
|
||||||
|
"babel-eslint": "^10.0.3",
|
||||||
|
"commitizen": "^3.0.5",
|
||||||
|
"cz-conventional-changelog": "^2.1.0",
|
||||||
|
"eslint": "^6.5.1",
|
||||||
|
"git-cz": "^4.3.1",
|
||||||
|
"husky": "^4.2.3",
|
||||||
|
"lerna": "^2.11.0",
|
||||||
|
"lint-staged": "^8.1.0",
|
||||||
|
"prettier": "^1.15.3",
|
||||||
|
"ts-node": "^7.0.1",
|
||||||
|
"tslib": "^1.9.3",
|
||||||
|
"typescript": "^3.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
52
packages/code-generator/CHANGELOG.md
Normal file
52
packages/code-generator/CHANGELOG.md
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
<a name="0.8.4"></a>
|
||||||
|
## [0.8.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-code-generator@0.8.3...@ali/lowcode-code-generator@0.8.4) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-code-generator
|
||||||
|
|
||||||
|
<a name="0.8.3"></a>
|
||||||
|
## [0.8.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-code-generator@0.8.2...@ali/lowcode-code-generator@0.8.3) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-code-generator
|
||||||
|
|
||||||
|
<a name="0.8.2"></a>
|
||||||
|
## 0.8.2 (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* code generator main process ([021d6e0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/021d6e0))
|
||||||
|
* demo schema & complex children type ([a5ee6bd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5ee6bd))
|
||||||
|
* fix gaps ([32af3d3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/32af3d3))
|
||||||
|
* project builder fix & publish demo to disk ([26983b3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/26983b3))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.1"></a>
|
||||||
|
## 0.8.1 (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
* code generator main process ([021d6e0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/021d6e0))
|
||||||
|
* demo schema & complex children type ([a5ee6bd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5ee6bd))
|
||||||
|
* fix gaps ([32af3d3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/32af3d3))
|
||||||
|
* project builder fix & publish demo to disk ([26983b3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/26983b3))
|
||||||
|
=======
|
||||||
|
* code generator main process ([021d6e0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/021d6e0fe9fb29a8b6c1c5d5f4d06ec71896faa5))
|
||||||
|
* demo schema & complex children type ([a5ee6bd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5ee6bd55806fc9aea695096ccd4c7f50b8e31c4))
|
||||||
|
* fix gaps ([32af3d3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/32af3d3a3ca4d5aca15be25e05c840c8ea0cb6ae))
|
||||||
|
* project builder fix & publish demo to disk ([26983b3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/26983b38c2b0f1d39d79964eb54d8ce60250dd82))
|
||||||
|
>>>>>>> df955e1db90ff104cd11160def80113cfd6faccc
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ali/lowcode-engine-code-generator",
|
"name": "@ali/lowcode-code-generator",
|
||||||
"version": "0.0.1",
|
"version": "0.8.4",
|
||||||
"description": "出码引擎 for LowCode Engine",
|
"description": "出码引擎 for LowCode Engine",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
81
packages/demo/CHANGELOG.md
Normal file
81
packages/demo/CHANGELOG.md
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
<a name="0.8.8"></a>
|
||||||
|
## [0.8.8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.7...@ali/lowcode-demo@0.8.8) (2020-03-31)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-demo
|
||||||
|
|
||||||
|
<a name="0.8.7"></a>
|
||||||
|
## [0.8.7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.6...@ali/lowcode-demo@0.8.7) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-demo
|
||||||
|
|
||||||
|
<a name="0.8.6"></a>
|
||||||
|
## [0.8.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.5...@ali/lowcode-demo@0.8.6) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-demo
|
||||||
|
|
||||||
|
<a name="0.8.5"></a>
|
||||||
|
## [0.8.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.4...@ali/lowcode-demo@0.8.5) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* depend ([c90996d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c90996d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.4"></a>
|
||||||
|
## [0.8.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.3...@ali/lowcode-demo@0.8.4) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-demo
|
||||||
|
|
||||||
|
<a name="0.8.3"></a>
|
||||||
|
## [0.8.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.2...@ali/lowcode-demo@0.8.3) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-demo
|
||||||
|
|
||||||
|
<a name="0.8.2"></a>
|
||||||
|
## 0.8.2 (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* complet preview ([56c16ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56c16ff))
|
||||||
|
* double outline & ZH_EN support ([b379bd7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b379bd7))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.1"></a>
|
||||||
|
## 0.8.1 (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
* complet preview ([56c16ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56c16ff))
|
||||||
|
* double outline & ZH_EN support ([b379bd7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b379bd7))
|
||||||
|
=======
|
||||||
|
* complet preview ([56c16ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56c16ffa5c39c2d01abd9cfa90fea49a4539da1d))
|
||||||
|
* double outline & ZH_EN support ([b379bd7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b379bd7c0c488ef24f825760750a13d3fa083c96))
|
||||||
|
>>>>>>> df955e1db90ff104cd11160def80113cfd6faccc
|
||||||
38
packages/demo/build.json
Normal file
38
packages/demo/build.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"entry": {
|
||||||
|
"index": "src/index.ts",
|
||||||
|
"react-simulator-renderer": "../react-simulator-renderer/src/index.ts",
|
||||||
|
"preview": "src/preview.ts"
|
||||||
|
},
|
||||||
|
"vendor": false,
|
||||||
|
"devServer": {
|
||||||
|
"hot": false
|
||||||
|
},
|
||||||
|
"publicPath": "/",
|
||||||
|
"externals": {
|
||||||
|
"react": "window.React",
|
||||||
|
"react-dom": "window.ReactDOM",
|
||||||
|
"prop-types": "window.PropTypes",
|
||||||
|
"@alifd/next": "window.Next"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"build-plugin-react-app"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"build-plugin-fusion",
|
||||||
|
{
|
||||||
|
"themePackage": "@alife/theme-lowcode-light"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"build-plugin-moment-locales",
|
||||||
|
{
|
||||||
|
"locales": [
|
||||||
|
"zh-cn"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"./build.plugin.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
13
packages/demo/build.plugin.js
Normal file
13
packages/demo/build.plugin.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||||
|
|
||||||
|
module.exports = ({ onGetWebpackConfig }) => {
|
||||||
|
onGetWebpackConfig((config) => {
|
||||||
|
config.resolve
|
||||||
|
.plugin('tsconfigpaths')
|
||||||
|
.use(TsconfigPathsPlugin, [{
|
||||||
|
configFile: "./tsconfig.json"
|
||||||
|
}]);
|
||||||
|
config.plugins.delete('hot');
|
||||||
|
config.devServer.hot(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
33
packages/demo/cloud-build.json
Normal file
33
packages/demo/cloud-build.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"entry": {
|
||||||
|
"lowcode-editor": "src/index.ts",
|
||||||
|
"lowcode-preview": "src/preview.ts"
|
||||||
|
},
|
||||||
|
"vendor": false,
|
||||||
|
"externals": {
|
||||||
|
"react": "window.React",
|
||||||
|
"react-dom": "window.ReactDOM",
|
||||||
|
"prop-types": "window.PropTypes",
|
||||||
|
"@ali/lowcode-globals": "window.LCEGlobals"
|
||||||
|
},
|
||||||
|
"minify": false,
|
||||||
|
"sourcemap": true,
|
||||||
|
"outputAssetsPath": {
|
||||||
|
"js": "", "css": ""
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
["build-plugin-react-app"],
|
||||||
|
[
|
||||||
|
"build-plugin-fusion",
|
||||||
|
{
|
||||||
|
"themePackage": "@alife/theme-lowcode-light"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"build-plugin-moment-locales",
|
||||||
|
{
|
||||||
|
"locales": ["zh-cn"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
46
packages/demo/package.json
Normal file
46
packages/demo/package.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "@ali/lowcode-demo",
|
||||||
|
"version": "0.8.8",
|
||||||
|
"private": true,
|
||||||
|
"description": "低代码引擎 DEMO",
|
||||||
|
"scripts": {
|
||||||
|
"cloud-build": "build-scripts build --config cloud-build.json",
|
||||||
|
"gen": "npm run genSkeleton && tyarn",
|
||||||
|
"genSkeleton": "iceluna gen lowcode -c ./skeleton.config.js -t ./src/editor/config",
|
||||||
|
"start": "build-scripts start"
|
||||||
|
},
|
||||||
|
"config": {},
|
||||||
|
"dependencies": {
|
||||||
|
"@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-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.7",
|
||||||
|
"@ali/lowcode-setters": "^0.8.6",
|
||||||
|
"@alifd/next": "^1.19.12",
|
||||||
|
"@alife/theme-lowcode-dark": "^0.1.0",
|
||||||
|
"@alife/theme-lowcode-light": "^0.1.0",
|
||||||
|
"react": "^16.8.1",
|
||||||
|
"react-dom": "^16.8.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@ali/iceluna-cli": "^0.0.16",
|
||||||
|
"@alib/build-scripts": "^0.1.18",
|
||||||
|
"@types/events": "^3.0.0",
|
||||||
|
"@types/react": "^16.8.3",
|
||||||
|
"@types/react-dom": "^16.8.2",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
1594
packages/demo/public/assets.json
Normal file
1594
packages/demo/public/assets.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
packages/demo/public/favicon.png
Normal file
BIN
packages/demo/public/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@ -15,7 +15,7 @@
|
|||||||
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="dark">
|
<body>
|
||||||
<div id="ice-container"></div>
|
<div id="lce-container"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
21
packages/demo/public/preview.html
Normal file
21
packages/demo/public/preview.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
<title>LowCodeEngine DEMO</title>
|
||||||
|
<script src="https://g.alicdn.com/code/lib/react/16.9.0/umd/react.development.js"></script>
|
||||||
|
<script src="https://g.alicdn.com/code/lib/react-dom/16.9.0/umd/react-dom.development.js"></script>
|
||||||
|
<script src="https://g.alicdn.com/code/lib/prop-types/15.7.2/prop-types.js"></script>
|
||||||
|
<script> React.PropTypes = PropTypes; </script>
|
||||||
|
<script src="https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://alifd.alicdn.com/npm/@alifd/next/1.11.6/next.min.css">
|
||||||
|
<script src="https://unpkg.alibaba-inc.com/@alifd/next@1.18.17/dist/next.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="lce-container"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
110
packages/demo/public/schema.json
Normal file
110
packages/demo/public/schema.json
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
{
|
||||||
|
"componentName": "Page",
|
||||||
|
"fileName": "test",
|
||||||
|
"dataSource": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"text": "outter"
|
||||||
|
},
|
||||||
|
"props": {
|
||||||
|
"ref": "outterView",
|
||||||
|
"autoLoading": true,
|
||||||
|
"style": {
|
||||||
|
"padding": 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"componentName": "Form",
|
||||||
|
"props": {
|
||||||
|
"labelCol": 3,
|
||||||
|
"style": {},
|
||||||
|
"ref": "testForm"
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"props": {
|
||||||
|
"label": "姓名:",
|
||||||
|
"name": "name",
|
||||||
|
"initValue": "李雷"
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"componentName": "Input",
|
||||||
|
"props": {
|
||||||
|
"placeholder": "请输入",
|
||||||
|
"size": "medium",
|
||||||
|
"style": {
|
||||||
|
"width": 320
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"props": {
|
||||||
|
"label": "年龄:",
|
||||||
|
"name": "age",
|
||||||
|
"initValue": "22"
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"componentName": "NumberPicker",
|
||||||
|
"props": {
|
||||||
|
"size": "medium",
|
||||||
|
"type": "normal"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"componentName": "Form.Item",
|
||||||
|
"props": {
|
||||||
|
"label": "职业:",
|
||||||
|
"name": "profession"
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"componentName": "Select",
|
||||||
|
"props": {
|
||||||
|
"dataSource": [{
|
||||||
|
"label": "教师",
|
||||||
|
"value": "t"
|
||||||
|
}, {
|
||||||
|
"label": "医生",
|
||||||
|
"value": "d"
|
||||||
|
}, {
|
||||||
|
"label": "歌手",
|
||||||
|
"value": "s"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"componentName": "Div",
|
||||||
|
"props": {
|
||||||
|
"style": {
|
||||||
|
"textAlign": "center"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"children": [{
|
||||||
|
"componentName": "Button.Group",
|
||||||
|
"props": {},
|
||||||
|
"children": [{
|
||||||
|
"componentName": "Button",
|
||||||
|
"props": {
|
||||||
|
"type": "primary",
|
||||||
|
"style": {
|
||||||
|
"margin": "0 5px 0 5px"
|
||||||
|
},
|
||||||
|
"htmlType": "submit"
|
||||||
|
},
|
||||||
|
"children": "提交"
|
||||||
|
}, {
|
||||||
|
"componentName": "Button",
|
||||||
|
"props": {
|
||||||
|
"type": "normal",
|
||||||
|
"style": {
|
||||||
|
"margin": "0 5px 0 5px"
|
||||||
|
},
|
||||||
|
"htmlType": "reset"
|
||||||
|
},
|
||||||
|
"children": "重置"
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}
|
||||||
155
packages/demo/skeleton.config.js
Normal file
155
packages/demo/skeleton.config.js
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
module.exports = {
|
||||||
|
skeleton: {
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-editor-skeleton',
|
||||||
|
version: '^0.8.0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
fusion: {
|
||||||
|
package: '@alife/theme-lowcode-light',
|
||||||
|
version: '^0.1.0'
|
||||||
|
},
|
||||||
|
scss: ''
|
||||||
|
},
|
||||||
|
constants: {
|
||||||
|
namespace: 'page'
|
||||||
|
},
|
||||||
|
utils: [],
|
||||||
|
plugins: {
|
||||||
|
topArea: [
|
||||||
|
{
|
||||||
|
pluginKey: 'logo',
|
||||||
|
type: 'Custom',
|
||||||
|
props: {
|
||||||
|
align: 'left',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-sample-logo',
|
||||||
|
version: '^0.8.0'
|
||||||
|
},
|
||||||
|
pluginProps: {
|
||||||
|
logo: 'https://img.alicdn.com/tfs/TB1hoI9x1H2gK0jSZFEXXcqMpXa-146-40.png',
|
||||||
|
href: '/'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pluginKey: 'undoRedo',
|
||||||
|
type: 'Custom',
|
||||||
|
props: {
|
||||||
|
align: 'right',
|
||||||
|
width: 88
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-undo-redo',
|
||||||
|
version: '^0.8.0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pluginKey: 'divider',
|
||||||
|
type: 'Divider',
|
||||||
|
props: {
|
||||||
|
align: 'right'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pluginKey: 'samplePreview',
|
||||||
|
type: 'Custom',
|
||||||
|
props: {
|
||||||
|
align: 'right',
|
||||||
|
width: 64
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-sample-preview',
|
||||||
|
version: '^0.8.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
leftArea: [
|
||||||
|
{
|
||||||
|
pluginKey: 'componentsPane',
|
||||||
|
type: 'PanelIcon',
|
||||||
|
props: {
|
||||||
|
align: 'top',
|
||||||
|
icon: 'zujianku',
|
||||||
|
title: '组件库',
|
||||||
|
floatable: true,
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-components-pane',
|
||||||
|
version: '^0.8.0'
|
||||||
|
},
|
||||||
|
pluginProps: {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pluginKey: 'outlinePane',
|
||||||
|
type: 'PanelIcon',
|
||||||
|
props: {
|
||||||
|
align: 'top',
|
||||||
|
icon: 'shuxingkongjian',
|
||||||
|
title: '大纲树'
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-outline-pane',
|
||||||
|
version: '^0.8.0'
|
||||||
|
},
|
||||||
|
pluginProps: {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pluginKey: 'zhEn',
|
||||||
|
type: 'Custom',
|
||||||
|
props: {
|
||||||
|
align: 'bottom',
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-zh-en',
|
||||||
|
version: '^0.8.0'
|
||||||
|
},
|
||||||
|
pluginProps: {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rightArea: [
|
||||||
|
{
|
||||||
|
pluginKey: 'settingsPane',
|
||||||
|
type: 'Panel',
|
||||||
|
props: {},
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-settings-pane',
|
||||||
|
version: '^0.8.0'
|
||||||
|
},
|
||||||
|
pluginProps: {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
centerArea: [
|
||||||
|
{
|
||||||
|
pluginKey: 'designer',
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-designer',
|
||||||
|
version: '^0.8.0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pluginKey: 'eventBindDialog',
|
||||||
|
config: {
|
||||||
|
package: '@ali/lowcode-plugin-event-bind-dialog',
|
||||||
|
version: '^0.8.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
hooks: [],
|
||||||
|
shortCuts: [],
|
||||||
|
lifeCycles: {
|
||||||
|
init: async function init(editor) {
|
||||||
|
const assets = await editor.utils.get('./assets.json');
|
||||||
|
editor.set('assets', assets);
|
||||||
|
editor.emit('assets.loaded', assets);
|
||||||
|
|
||||||
|
const schema = await editor.utils.get('./schema.json');
|
||||||
|
editor.set('schema', schema);
|
||||||
|
editor.emit('schema.loaded', schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
21
packages/demo/src/app/config/app.ts
Normal file
21
packages/demo/src/app/config/app.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export default {
|
||||||
|
sdkVersion: '1.0.3',
|
||||||
|
history: 'hash', // 浏览器路由:brower 哈希路由:hash
|
||||||
|
containerId: 'lce-container',
|
||||||
|
layout: {
|
||||||
|
componentName: 'BasicLayout',
|
||||||
|
props: {
|
||||||
|
name: '低代码引擎预览 demo',
|
||||||
|
logo: {
|
||||||
|
src: 'https://img.alicdn.com/tfs/TB1L.1QAeL2gK0jSZFmXXc7iXXa-90-90.png',
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
package: '@alife/theme-fusion',
|
||||||
|
version: '^0.1.0',
|
||||||
|
},
|
||||||
|
compDependencies: [],
|
||||||
|
};
|
||||||
5
packages/demo/src/app/config/components.ts
Normal file
5
packages/demo/src/app/config/components.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* 内置组件
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {};
|
||||||
53
packages/demo/src/app/config/componentsMap.ts
Normal file
53
packages/demo/src/app/config/componentsMap.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
export default {
|
||||||
|
Button: {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Button',
|
||||||
|
},
|
||||||
|
'Button.Group': {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Button',
|
||||||
|
subName: 'Group',
|
||||||
|
},
|
||||||
|
Input: {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Input',
|
||||||
|
},
|
||||||
|
Form: {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Form',
|
||||||
|
},
|
||||||
|
'Form.Item': {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Form',
|
||||||
|
subName: 'Item',
|
||||||
|
},
|
||||||
|
NumberPicker: {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'NumberPicker',
|
||||||
|
},
|
||||||
|
Select: {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Select',
|
||||||
|
},
|
||||||
|
'Select.Option': {
|
||||||
|
package: '@alifd/next',
|
||||||
|
version: '1.19.18',
|
||||||
|
destructuring: true,
|
||||||
|
exportName: 'Select',
|
||||||
|
subName: 'Option',
|
||||||
|
},
|
||||||
|
};
|
||||||
20
packages/demo/src/app/index.ts
Normal file
20
packages/demo/src/app/index.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { app } from '@ali/lowcode-runtime';
|
||||||
|
import Renderer from '@ali/lowcode-react-renderer';
|
||||||
|
import FusionLoading from './plugins/loading/fusion';
|
||||||
|
import BasicLayout from './layouts/BasicLayout';
|
||||||
|
import Preview from './plugins/provider';
|
||||||
|
|
||||||
|
// 注册渲染模块
|
||||||
|
app.registerRenderer(Renderer);
|
||||||
|
|
||||||
|
// 注册布局组件,可注册多个
|
||||||
|
app.registerLayout('BasicLayout', BasicLayout);
|
||||||
|
|
||||||
|
// 注册页面 Loading
|
||||||
|
app.registerLoading(FusionLoading);
|
||||||
|
|
||||||
|
// appKey:应用唯一标识
|
||||||
|
app.registerProvider(Preview);
|
||||||
|
|
||||||
|
// 启动应用
|
||||||
|
app.run();
|
||||||
24
packages/demo/src/app/layouts/BasicLayout/index.scss
Normal file
24
packages/demo/src/app/layouts/BasicLayout/index.scss
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
$header-height: 52px;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic-shell {
|
||||||
|
min-height: 100vh;
|
||||||
|
.next-shell-header {
|
||||||
|
height: $header-height;
|
||||||
|
}
|
||||||
|
.next-shell-main {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
min-height: calc(100% - $header-height);
|
||||||
|
.next-shell-sub-main {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
packages/demo/src/app/layouts/BasicLayout/index.tsx
Normal file
34
packages/demo/src/app/layouts/BasicLayout/index.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Search, Icon, Shell } from '@alifd/next';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
export default ({
|
||||||
|
name,
|
||||||
|
children,
|
||||||
|
logo,
|
||||||
|
}: {
|
||||||
|
name: string;
|
||||||
|
children: any;
|
||||||
|
logo: { src: string; width: number; height: number };
|
||||||
|
}) => (
|
||||||
|
<Shell className="basic-shell" style={{ border: '1px solid #eee' }}>
|
||||||
|
<Shell.Branding>
|
||||||
|
<img src={logo.src} width={logo.width} height={logo.height} alt="logo" />
|
||||||
|
<span style={{ marginLeft: 10 }}>{name}</span>
|
||||||
|
</Shell.Branding>
|
||||||
|
<Shell.Navigation direction="hoz">
|
||||||
|
<Search key="2" shape="simple" type="dark" style={{ width: '200px' }} />
|
||||||
|
</Shell.Navigation>
|
||||||
|
<Shell.Action>
|
||||||
|
<Icon type="ic_tongzhi" />
|
||||||
|
<img src="https://img.alicdn.com/tfs/TB1.ZBecq67gK0jSZFHXXa9jVXa-904-826.png" className="avatar" alt="用户头像" />
|
||||||
|
<span style={{ marginLeft: 10 }}>MyName</span>
|
||||||
|
</Shell.Action>
|
||||||
|
|
||||||
|
<Shell.Content className="content">{children}</Shell.Content>
|
||||||
|
|
||||||
|
<Shell.Footer>
|
||||||
|
<span>Alibaba Fusion</span>
|
||||||
|
<span>@ 2019 Alibaba Piecework 版权所有</span>
|
||||||
|
</Shell.Footer>
|
||||||
|
</Shell>
|
||||||
|
);
|
||||||
9
packages/demo/src/app/plugins/loading/fusion/index.scss
Normal file
9
packages/demo/src/app/plugins/loading/fusion/index.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.fusion-loading {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
margin-top: -24px;
|
||||||
|
margin-left: -24px;
|
||||||
|
}
|
||||||
4
packages/demo/src/app/plugins/loading/fusion/index.tsx
Normal file
4
packages/demo/src/app/plugins/loading/fusion/index.tsx
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { Loading } from '@alifd/next';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
export default () => <Loading tip="加载中..." className="fusion-loading" />;
|
||||||
51
packages/demo/src/app/plugins/provider.ts
Normal file
51
packages/demo/src/app/plugins/provider.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { ReactProvider, Utils } from '@ali/lowcode-runtime';
|
||||||
|
import appConfig from '../config/app';
|
||||||
|
import builtInComps from '../config/components';
|
||||||
|
import componentsMap from '../config/componentsMap';
|
||||||
|
import constants from '../config/constants';
|
||||||
|
import utils from '../config/utils';
|
||||||
|
|
||||||
|
// 定制加载应用配置的逻辑
|
||||||
|
export default class Preview extends ReactProvider {
|
||||||
|
// 定制获取、处理应用配置(组件、插件、路由模式、布局等)的逻辑
|
||||||
|
async getAppData(): Promise<any> {
|
||||||
|
const { history, layout, containerId } = appConfig;
|
||||||
|
const appSchemaStr: any = localStorage.getItem('lce-dev-store');
|
||||||
|
if (!appSchemaStr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const appSchema = JSON.parse(appSchemaStr);
|
||||||
|
if (!appSchema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const routes: any = {};
|
||||||
|
appSchema.componentsTree.forEach((page: any) => {
|
||||||
|
if (!page.fileName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pageId = page.fileName;
|
||||||
|
routes[pageId] = `/${pageId}`;
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
history,
|
||||||
|
layout,
|
||||||
|
routes,
|
||||||
|
containerId,
|
||||||
|
components: { ...builtInComps, ...Utils.buildComponents({ '@alifd/next': 'Next' }, componentsMap) },
|
||||||
|
componentsMap,
|
||||||
|
utils: utils,
|
||||||
|
constants,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定制获取、处理页面 schema 的逻辑
|
||||||
|
async getPageData(pageId: string) {
|
||||||
|
const appSchemaStr = localStorage.getItem('lce-dev-store');
|
||||||
|
const appSchema = JSON.parse(appSchemaStr || '');
|
||||||
|
const idx = appSchema.componentsTree.findIndex(
|
||||||
|
(page: any, idx: number) => (page.fileName || `page${idx}`) === pageId,
|
||||||
|
);
|
||||||
|
const schema = appSchema.componentsTree[idx];
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
22
packages/demo/src/editor/config/components.js
Normal file
22
packages/demo/src/editor/config/components.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import LowcodeSkeleton from '@ali/lowcode-editor-skeleton';
|
||||||
|
import logo from '@ali/lowcode-plugin-sample-logo';
|
||||||
|
import undoRedo from '@ali/lowcode-plugin-undo-redo';
|
||||||
|
import samplePreview from '@ali/lowcode-plugin-sample-preview';
|
||||||
|
import componentsPane from '@ali/lowcode-plugin-components-pane';
|
||||||
|
import outlinePane from '@ali/lowcode-plugin-outline-pane';
|
||||||
|
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';
|
||||||
|
export default {
|
||||||
|
LowcodeSkeleton,
|
||||||
|
logo,
|
||||||
|
undoRedo,
|
||||||
|
samplePreview,
|
||||||
|
componentsPane,
|
||||||
|
outlinePane,
|
||||||
|
zhEn,
|
||||||
|
settingsPane,
|
||||||
|
designer,
|
||||||
|
eventBindDialog
|
||||||
|
};
|
||||||
3
packages/demo/src/editor/config/constants.js
Normal file
3
packages/demo/src/editor/config/constants.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
"namespace": "page"
|
||||||
|
}
|
||||||
@ -7,4 +7,4 @@ export default {
|
|||||||
'zh-CN': zh_cn,
|
'zh-CN': zh_cn,
|
||||||
'zh-TW': zh_tw,
|
'zh-TW': zh_tw,
|
||||||
'ja-JP': ja_jp
|
'ja-JP': ja_jp
|
||||||
};
|
};
|
||||||
1
packages/demo/src/editor/config/locale/zh-CN.js
Normal file
1
packages/demo/src/editor/config/locale/zh-CN.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default {};
|
||||||
1
packages/demo/src/editor/config/locale/zh-TW.js
Normal file
1
packages/demo/src/editor/config/locale/zh-TW.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default {};
|
||||||
140
packages/demo/src/editor/config/skeleton.js
Normal file
140
packages/demo/src/editor/config/skeleton.js
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
export default {
|
||||||
|
"skeleton": {
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-editor-skeleton",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"theme": {
|
||||||
|
"fusion": {
|
||||||
|
"package": "@alife/theme-lowcode-light",
|
||||||
|
"version": "^0.1.0"
|
||||||
|
},
|
||||||
|
"scss": ""
|
||||||
|
},
|
||||||
|
"constants": {
|
||||||
|
"namespace": "page"
|
||||||
|
},
|
||||||
|
"utils": [],
|
||||||
|
"plugins": {
|
||||||
|
"topArea": [{
|
||||||
|
"pluginKey": "logo",
|
||||||
|
"type": "Custom",
|
||||||
|
"props": {
|
||||||
|
"align": "left",
|
||||||
|
"width": 100
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-sample-logo",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
},
|
||||||
|
"pluginProps": {
|
||||||
|
"logo": "https://img.alicdn.com/tfs/TB1hoI9x1H2gK0jSZFEXXcqMpXa-146-40.png",
|
||||||
|
"href": "/"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"pluginKey": "undoRedo",
|
||||||
|
"type": "Custom",
|
||||||
|
"props": {
|
||||||
|
"align": "right",
|
||||||
|
"width": 88
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-undo-redo",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"pluginKey": "divider",
|
||||||
|
"type": "Divider",
|
||||||
|
"props": {
|
||||||
|
"align": "right"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"pluginKey": "samplePreview",
|
||||||
|
"type": "Custom",
|
||||||
|
"props": {
|
||||||
|
"align": "right",
|
||||||
|
"width": 64
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-sample-preview",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"leftArea": [{
|
||||||
|
"pluginKey": "componentsPane",
|
||||||
|
"type": "PanelIcon",
|
||||||
|
"props": {
|
||||||
|
"align": "top",
|
||||||
|
"icon": "zujianku",
|
||||||
|
"title": "组件库",
|
||||||
|
"floatable": true
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-components-pane",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
},
|
||||||
|
"pluginProps": {}
|
||||||
|
}, {
|
||||||
|
"pluginKey": "outlinePane",
|
||||||
|
"type": "PanelIcon",
|
||||||
|
"props": {
|
||||||
|
"align": "top",
|
||||||
|
"icon": "shuxingkongjian",
|
||||||
|
"title": "大纲树"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-outline-pane",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
},
|
||||||
|
"pluginProps": {}
|
||||||
|
}, {
|
||||||
|
"pluginKey": "zhEn",
|
||||||
|
"type": "Custom",
|
||||||
|
"props": {
|
||||||
|
"align": "bottom"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-zh-en",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
},
|
||||||
|
"pluginProps": {}
|
||||||
|
}],
|
||||||
|
"rightArea": [{
|
||||||
|
"pluginKey": "settingsPane",
|
||||||
|
"type": "Panel",
|
||||||
|
"props": {},
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-settings-pane",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
},
|
||||||
|
"pluginProps": {}
|
||||||
|
}],
|
||||||
|
"centerArea": [{
|
||||||
|
"pluginKey": "designer",
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-designer",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"pluginKey": "eventBindDialog",
|
||||||
|
"config": {
|
||||||
|
"package": "@ali/lowcode-plugin-event-bind-dialog",
|
||||||
|
"version": "^0.8.0"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
"hooks": [],
|
||||||
|
"shortCuts": [],
|
||||||
|
"lifeCycles": {
|
||||||
|
"init": async function init(editor) {
|
||||||
|
const assets = await editor.utils.get('./assets.json');
|
||||||
|
editor.set('assets', assets);
|
||||||
|
editor.emit('assets.loaded', assets);
|
||||||
|
|
||||||
|
const schema = await editor.utils.get('./schema.json');
|
||||||
|
editor.set('schema', schema);
|
||||||
|
editor.emit('schema.loaded', schema);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
3
packages/demo/src/editor/config/utils.js
Normal file
3
packages/demo/src/editor/config/utils.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
|
||||||
|
};
|
||||||
20
packages/demo/src/editor/index.tsx
Normal file
20
packages/demo/src/editor/index.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { registerSetters } from '@ali/lowcode-setters';
|
||||||
|
import config from './config/skeleton';
|
||||||
|
import components from './config/components';
|
||||||
|
import utils from './config/utils';
|
||||||
|
|
||||||
|
import './global.scss';
|
||||||
|
import './config/theme.scss';
|
||||||
|
|
||||||
|
registerSetters();
|
||||||
|
const Skeleton = components.LowcodeSkeleton;
|
||||||
|
const LCE_CONTAINER = document.getElementById('lce-container');
|
||||||
|
|
||||||
|
if (!LCE_CONTAINER) {
|
||||||
|
throw new Error('当前页面不存在 <div id="lce-container"></div> 节点.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
ReactDOM.render(<Skeleton config={config} utils={utils} components={components} />, LCE_CONTAINER);
|
||||||
1
packages/demo/src/index.ts
Normal file
1
packages/demo/src/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
import './editor';
|
||||||
1
packages/demo/src/preview.ts
Normal file
1
packages/demo/src/preview.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
import './app';
|
||||||
9
packages/demo/tsconfig.json
Normal file
9
packages/demo/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src/"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,16 +0,0 @@
|
|||||||
# EditorConfig is awesome: http://EditorConfig.org
|
|
||||||
|
|
||||||
# top-most EditorConfig file
|
|
||||||
root = true
|
|
||||||
|
|
||||||
# Tab indentation
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
build/
|
|
||||||
.*
|
|
||||||
~*
|
|
||||||
node_modules
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./node_modules/@recore/config/.eslintrc"
|
|
||||||
}
|
|
||||||
41
packages/designer/.gitignore
vendored
41
packages/designer/.gitignore
vendored
@ -1,41 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
coverage/
|
|
||||||
build/
|
|
||||||
dist/
|
|
||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
.theia/
|
|
||||||
.recore/
|
|
||||||
demo/
|
|
||||||
~*
|
|
||||||
package-lock.json
|
|
||||||
|
|
||||||
# Packages #
|
|
||||||
############
|
|
||||||
# it's better to unpack these files and commit the raw source
|
|
||||||
# git has its own built in compression methods
|
|
||||||
*.7z
|
|
||||||
*.dmg
|
|
||||||
*.gz
|
|
||||||
*.iso
|
|
||||||
*.jar
|
|
||||||
*.rar
|
|
||||||
*.tar
|
|
||||||
*.zip
|
|
||||||
|
|
||||||
# Logs and databases #
|
|
||||||
######################
|
|
||||||
*.log
|
|
||||||
*.sql
|
|
||||||
*.sqlite
|
|
||||||
|
|
||||||
# OS generated files #
|
|
||||||
######################
|
|
||||||
.DS_Store
|
|
||||||
.Trash*
|
|
||||||
*.swp
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"printWidth": 120,
|
|
||||||
"trailingComma": "all"
|
|
||||||
}
|
|
||||||
74
packages/designer/CHANGELOG.md
Normal file
74
packages/designer/CHANGELOG.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
<a name="0.9.1"></a>
|
||||||
|
## [0.9.1](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.0...@ali/lowcode-designer@0.9.1) (2020-03-31)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-designer
|
||||||
|
|
||||||
|
<a name="0.9.0"></a>
|
||||||
|
# [0.9.0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.8.5...@ali/lowcode-designer@0.9.0) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **designer:** fix insertion style ([82c10d2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/82c10d2))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **designer:** add blank page logic ([aeeb9ba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/aeeb9ba))
|
||||||
|
* **designer:** add builtin hotkeys ([2ec5883](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2ec5883))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.5"></a>
|
||||||
|
## [0.8.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.8.4...@ali/lowcode-designer@0.8.5) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-designer
|
||||||
|
|
||||||
|
<a name="0.8.4"></a>
|
||||||
|
## [0.8.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.8.3...@ali/lowcode-designer@0.8.4) (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @ali/lowcode-designer
|
||||||
|
|
||||||
|
<a name="0.8.3"></a>
|
||||||
|
## 0.8.3 (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* 🎸 merge material-parser ([b40c286](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b40c286))
|
||||||
|
* history log ([fbb3577](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fbb3577))
|
||||||
|
* import react-docgen to parse propTypes ([6e66168](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6e66168))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.8.2"></a>
|
||||||
|
## 0.8.2 (2020-03-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
* 🎸 merge material-parser ([b40c286](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b40c286))
|
||||||
|
* history log ([fbb3577](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fbb3577))
|
||||||
|
* import react-docgen to parse propTypes ([6e66168](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6e66168))
|
||||||
|
=======
|
||||||
|
* 🎸 merge material-parser ([b40c286](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b40c2869a0bc901d855279735fe86b84dabaa04d))
|
||||||
|
* history log ([fbb3577](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/fbb3577bd434c0ac77cc907abc36e3efe110fe8c))
|
||||||
|
* import react-docgen to parse propTypes ([6e66168](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6e661686e4693e69279c496f3be1dd173703c55e))
|
||||||
|
>>>>>>> df955e1db90ff104cd11160def80113cfd6faccc
|
||||||
@ -1 +1,4 @@
|
|||||||
编排模块
|
编排模块
|
||||||
|
|
||||||
|
|
||||||
|
simulator/renderer 发 CDN
|
||||||
|
|||||||
7
packages/designer/build.json
Normal file
7
packages/designer/build.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
[
|
||||||
|
"build-plugin-component"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
9380
packages/designer/package-lock.json
generated
9380
packages/designer/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,40 +1,45 @@
|
|||||||
{
|
{
|
||||||
"name": "lowcode-designer",
|
"name": "@ali/lowcode-designer",
|
||||||
"version": "0.9.0",
|
"version": "0.9.1",
|
||||||
"description": "alibaba lowcode designer",
|
"description": "Designer for Ali LowCode Engine",
|
||||||
"main": "src/index.ts",
|
"main": "lib/index.js",
|
||||||
"author": "",
|
"module": "es/index.js",
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"es"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "build-scripts build --skip-demo",
|
||||||
|
"test": "ava",
|
||||||
|
"test:snapshot": "ava --update-snapshots"
|
||||||
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ali/iceluna-sdk": "^1.0.5-beta.12",
|
"@ali/lowcode-globals": "^0.9.1",
|
||||||
"@recore/obx": "^1.0.8",
|
|
||||||
"@recore/obx-react": "^1.0.7",
|
|
||||||
"@types/medium-editor": "^5.0.3",
|
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"react": "^16",
|
"react": "^16",
|
||||||
"react-dom": "^16.7.0"
|
"react-dom": "^16.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@recore/config": "^2.0.0",
|
"@alib/build-scripts": "^0.1.18",
|
||||||
"@types/classnames": "^2.2.7",
|
"@types/classnames": "^2.2.7",
|
||||||
"@types/jest": "^24.0.16",
|
"@types/medium-editor": "^5.0.3",
|
||||||
"@types/node": "^13.7.1",
|
"@types/node": "^13.7.1",
|
||||||
"@types/react": "^16",
|
"@types/react": "^16",
|
||||||
"@types/react-dom": "^16",
|
"@types/react-dom": "^16",
|
||||||
"eslint": "^6.5.1",
|
"build-plugin-component": "^0.2.10"
|
||||||
"husky": "^1.1.2",
|
|
||||||
"jest": "^23.4.1",
|
|
||||||
"lint-staged": "^7.1.2",
|
|
||||||
"prettier": "^1.18.2",
|
|
||||||
"ts-jest": "^24.0.2",
|
|
||||||
"ts-node": "^8.0.1",
|
|
||||||
"tslib": "^1.9.3",
|
|
||||||
"typescript": "^3.1.3"
|
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"ava": {
|
||||||
"./src/**/*.{ts,tsx}": [
|
"compileEnhancements": false,
|
||||||
"eslint --fix",
|
"snapshotDir": "test/fixtures/__snapshots__",
|
||||||
"git add"
|
"extensions": [
|
||||||
|
"ts"
|
||||||
|
],
|
||||||
|
"require": [
|
||||||
|
"ts-node/register"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npm.alibaba-inc.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/designer/src/builtin-simulator/README.md
Normal file
1
packages/designer/src/builtin-simulator/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
内置模拟器主进程
|
||||||
@ -1,4 +1,4 @@
|
|||||||
.lc-auxiliary {
|
.lc-bem-tools {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -1,12 +1,11 @@
|
|||||||
import { Component, Fragment, PureComponent } from 'react';
|
import { Component, Fragment, PureComponent } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { observer } from '@recore/obx-react';
|
import { computed, observer, TitleContent, Title } from '@ali/lowcode-globals';
|
||||||
import { SimulatorContext } from '../context';
|
import { SimulatorContext } from '../context';
|
||||||
import { SimulatorHost } from '../host';
|
import { BuiltinSimulatorHost } from '../host';
|
||||||
import { computed } from '@recore/obx';
|
|
||||||
|
|
||||||
export class OutlineHoveringInstance extends PureComponent<{
|
export class BorderHoveringInstance extends PureComponent<{
|
||||||
title: string;
|
title: TitleContent;
|
||||||
rect: DOMRect | null;
|
rect: DOMRect | null;
|
||||||
scale: number;
|
scale: number;
|
||||||
scrollX: number;
|
scrollX: number;
|
||||||
@ -24,7 +23,7 @@ export class OutlineHoveringInstance extends PureComponent<{
|
|||||||
transform: `translate(${(scrollX + rect.left) * scale}px, ${(scrollY + rect.top) * scale}px)`,
|
transform: `translate(${(scrollX + rect.left) * scale}px, ${(scrollY + rect.top) * scale}px)`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const className = classNames('lc-outlines lc-outlines-hovering');
|
const className = classNames('lc-borders lc-borders-hovering');
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// 1. thinkof icon
|
// 1. thinkof icon
|
||||||
@ -32,14 +31,14 @@ export class OutlineHoveringInstance extends PureComponent<{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className} style={style}>
|
<div className={className} style={style}>
|
||||||
<a className="lc-outlines-title">{title}</a>
|
<Title title={title} className="lc-borders-title" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class OutlineHovering extends Component {
|
export class BorderHovering extends Component {
|
||||||
static contextType = SimulatorContext;
|
static contextType = SimulatorContext;
|
||||||
|
|
||||||
shouldComponentUpdate() {
|
shouldComponentUpdate() {
|
||||||
@ -47,19 +46,19 @@ export class OutlineHovering extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@computed get scale() {
|
@computed get scale() {
|
||||||
return (this.context as SimulatorHost).viewport.scale;
|
return (this.context as BuiltinSimulatorHost).viewport.scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get scrollX() {
|
@computed get scrollX() {
|
||||||
return (this.context as SimulatorHost).viewport.scrollX;
|
return (this.context as BuiltinSimulatorHost).viewport.scrollX;
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get scrollY() {
|
@computed get scrollY() {
|
||||||
return (this.context as SimulatorHost).viewport.scrollY;
|
return (this.context as BuiltinSimulatorHost).viewport.scrollY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed get current() {
|
@computed get current() {
|
||||||
const host = this.context as SimulatorHost;
|
const host = this.context as BuiltinSimulatorHost;
|
||||||
const doc = host.document;
|
const doc = host.document;
|
||||||
const selection = doc.selection;
|
const selection = doc.selection;
|
||||||
const current = host.designer.hovering.current;
|
const current = host.designer.hovering.current;
|
||||||
@ -70,7 +69,7 @@ export class OutlineHovering extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const host = this.context as SimulatorHost;
|
const host = this.context as BuiltinSimulatorHost;
|
||||||
const current = this.current;
|
const current = this.current;
|
||||||
if (!current || host.viewport.scrolling) {
|
if (!current || host.viewport.scrolling) {
|
||||||
return <Fragment />;
|
return <Fragment />;
|
||||||
@ -82,26 +81,26 @@ export class OutlineHovering extends Component {
|
|||||||
|
|
||||||
if (instances.length === 1) {
|
if (instances.length === 1) {
|
||||||
return (
|
return (
|
||||||
<OutlineHoveringInstance
|
<BorderHoveringInstance
|
||||||
key="line-h"
|
key="line-h"
|
||||||
title={current.title}
|
title={current.title}
|
||||||
scale={this.scale}
|
scale={this.scale}
|
||||||
scrollX={this.scrollX}
|
scrollX={this.scrollX}
|
||||||
scrollY={this.scrollY}
|
scrollY={this.scrollY}
|
||||||
rect={host.computeComponentInstanceRect(instances[0])}
|
rect={host.computeComponentInstanceRect(instances[0], current.componentMeta.rectSelector)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{instances.map((inst, i) => (
|
{instances.map((inst, i) => (
|
||||||
<OutlineHoveringInstance
|
<BorderHoveringInstance
|
||||||
key={`line-h-${i}`}
|
key={`line-h-${i}`}
|
||||||
title={current.title}
|
title={current.title}
|
||||||
scale={this.scale}
|
scale={this.scale}
|
||||||
scrollX={this.scrollX}
|
scrollX={this.scrollX}
|
||||||
scrollY={this.scrollY}
|
scrollY={this.scrollY}
|
||||||
rect={host.computeComponentInstanceRect(inst)}
|
rect={host.computeComponentInstanceRect(inst, current.componentMeta.rectSelector)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
@ -0,0 +1,225 @@
|
|||||||
|
import {
|
||||||
|
Component,
|
||||||
|
Fragment,
|
||||||
|
ReactNodeArray,
|
||||||
|
isValidElement,
|
||||||
|
cloneElement,
|
||||||
|
createElement,
|
||||||
|
ReactNode,
|
||||||
|
ComponentType,
|
||||||
|
} from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {
|
||||||
|
observer,
|
||||||
|
computed,
|
||||||
|
createIcon,
|
||||||
|
EmbedTip,
|
||||||
|
isReactComponent,
|
||||||
|
ActionContentObject,
|
||||||
|
isActionContentObject,
|
||||||
|
} from '@ali/lowcode-globals';
|
||||||
|
import { SimulatorContext } from '../context';
|
||||||
|
import { BuiltinSimulatorHost } from '../host';
|
||||||
|
import { OffsetObserver } from '../../../designer';
|
||||||
|
import { Node } from '../../../document';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class BorderSelectingInstance extends Component<{
|
||||||
|
observed: OffsetObserver;
|
||||||
|
highlight?: boolean;
|
||||||
|
dragging?: boolean;
|
||||||
|
}> {
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.props.observed.purge();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { observed, highlight, dragging } = this.props;
|
||||||
|
if (!observed.hasOffset) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed;
|
||||||
|
|
||||||
|
const style = {
|
||||||
|
width: offsetWidth,
|
||||||
|
height: offsetHeight,
|
||||||
|
transform: `translate3d(${offsetLeft}px, ${offsetTop}px, 0)`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const className = classNames('lc-borders lc-borders-selecting', {
|
||||||
|
highlight,
|
||||||
|
dragging,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className} style={style}>
|
||||||
|
{!dragging && <Toolbar observed={observed} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
class Toolbar extends Component<{ observed: OffsetObserver }> {
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { observed } = this.props;
|
||||||
|
const { height, width } = observed.viewport;
|
||||||
|
const BAR_HEIGHT = 20;
|
||||||
|
const MARGIN = 1;
|
||||||
|
const BORDER = 2;
|
||||||
|
const SPACE_HEIGHT = BAR_HEIGHT + MARGIN + BORDER;
|
||||||
|
let style: any;
|
||||||
|
if (observed.top > SPACE_HEIGHT) {
|
||||||
|
style = {
|
||||||
|
right: Math.max(-BORDER, observed.right - width - BORDER),
|
||||||
|
top: -SPACE_HEIGHT,
|
||||||
|
height: BAR_HEIGHT,
|
||||||
|
};
|
||||||
|
} else if (observed.bottom + SPACE_HEIGHT < height) {
|
||||||
|
style = {
|
||||||
|
bottom: -SPACE_HEIGHT,
|
||||||
|
height: BAR_HEIGHT,
|
||||||
|
right: Math.max(-BORDER, observed.right - width - BORDER),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
style = {
|
||||||
|
height: BAR_HEIGHT,
|
||||||
|
top: Math.max(MARGIN, MARGIN - observed.top),
|
||||||
|
right: Math.max(MARGIN, MARGIN + observed.right - width),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const { node } = observed;
|
||||||
|
const actions: ReactNodeArray = [];
|
||||||
|
node.componentMeta.availableActions.forEach(action => {
|
||||||
|
const { important, condition, content, name } = action;
|
||||||
|
if (node.isSlotRoot && (name === 'copy' || name === 'remove')) {
|
||||||
|
// FIXME: need this?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (important && (typeof condition === 'function' ? condition(node) : condition !== false)) {
|
||||||
|
actions.push(createAction(content, name, node));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div className="lc-borders-actions" style={style}>
|
||||||
|
{actions}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAction(content: ReactNode | ComponentType<any> | ActionContentObject, key: string, node: Node) {
|
||||||
|
if (isValidElement(content)) {
|
||||||
|
return cloneElement(content, { key, node });
|
||||||
|
}
|
||||||
|
if (isReactComponent(content)) {
|
||||||
|
return createElement(content, { key, node });
|
||||||
|
}
|
||||||
|
if (isActionContentObject(content)) {
|
||||||
|
const { action, description, icon } = content;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
className="lc-borders-action"
|
||||||
|
onClick={() => {
|
||||||
|
action && action(node);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon && createIcon(icon)}
|
||||||
|
<EmbedTip>{description}</EmbedTip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class BorderSelectingForNode extends Component<{ node: Node }> {
|
||||||
|
static contextType = SimulatorContext;
|
||||||
|
|
||||||
|
get host(): BuiltinSimulatorHost {
|
||||||
|
return this.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
get dragging(): boolean {
|
||||||
|
return this.host.designer.dragon.dragging;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get instances() {
|
||||||
|
return this.host.getComponentInstances(this.props.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { instances } = this;
|
||||||
|
const { node } = this.props;
|
||||||
|
const designer = this.host.designer;
|
||||||
|
|
||||||
|
if (!instances || instances.length < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Fragment key={node.id}>
|
||||||
|
{instances.map(instance => {
|
||||||
|
const observed = designer.createOffsetObserver({
|
||||||
|
node,
|
||||||
|
instance,
|
||||||
|
});
|
||||||
|
if (!observed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return <BorderSelectingInstance key={observed.id} dragging={this.dragging} observed={observed} />;
|
||||||
|
})}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class BorderSelecting extends Component {
|
||||||
|
static contextType = SimulatorContext;
|
||||||
|
|
||||||
|
get host(): BuiltinSimulatorHost {
|
||||||
|
return this.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
get dragging(): boolean {
|
||||||
|
return this.host.designer.dragon.dragging;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get selecting() {
|
||||||
|
const doc = this.host.document;
|
||||||
|
if (doc.suspensed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const selection = doc.selection;
|
||||||
|
return this.dragging ? selection.getTopNodes() : selection.getNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const selecting = this.selecting;
|
||||||
|
if (!selecting || selecting.length < 1) {
|
||||||
|
// DIRTY FIX, recore has a bug!
|
||||||
|
return <Fragment />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{selecting.map(node => (
|
||||||
|
<BorderSelectingForNode key={node.id} node={node} />
|
||||||
|
))}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
@scope: lc-outlines;
|
@scope: lc-borders;
|
||||||
|
|
||||||
.@{scope} {
|
.@{scope} {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -18,6 +18,32 @@
|
|||||||
transform: translateY(-100%);
|
transform: translateY(-100%);
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
}
|
}
|
||||||
|
& > &-actions {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: flex-end;
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-action {
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: var(--color-brand, #006cff);
|
||||||
|
opacity: 1;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
color: white;
|
||||||
|
&:hover {
|
||||||
|
background: var(--color-brand-light, #006cff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&&-hovering {
|
&&-hovering {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
30
packages/designer/src/builtin-simulator/bem-tools/index.tsx
Normal file
30
packages/designer/src/builtin-simulator/bem-tools/index.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { Component } from 'react';
|
||||||
|
import { observer } from '@ali/lowcode-globals';
|
||||||
|
import { BorderHovering } from './border-hovering';
|
||||||
|
import { SimulatorContext } from '../context';
|
||||||
|
import { BuiltinSimulatorHost } from '../host';
|
||||||
|
import { BorderSelecting } from './border-selecting';
|
||||||
|
import { InsertionView } from './insertion';
|
||||||
|
import './bem-tools.less';
|
||||||
|
import './borders.less';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class BemTools extends Component {
|
||||||
|
static contextType = SimulatorContext;
|
||||||
|
|
||||||
|
shouldComponentUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const host = this.context as BuiltinSimulatorHost;
|
||||||
|
const { scrollX, scrollY, scale } = host.viewport;
|
||||||
|
return (
|
||||||
|
<div className="lc-bem-tools" style={{ transform: `translate(${-scrollX * scale}px,${-scrollY * scale}px)` }}>
|
||||||
|
<BorderHovering key="hovering" />
|
||||||
|
<BorderSelecting key="selecting" />
|
||||||
|
<InsertionView key="insertion" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,23 +1,28 @@
|
|||||||
.lc-insertion {
|
.lc-insertion {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -1.5px;
|
top: -2px;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 12;
|
z-index: 12;
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
background-color: var(--color-brand-light);
|
background-color: var(--color-brand-light);
|
||||||
height: 3px;
|
height: 4px;
|
||||||
|
|
||||||
&.cover {
|
&.cover {
|
||||||
top: 0;
|
top: 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
border: none;
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.vertical {
|
&.vertical {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: -1.5px;
|
left: -2px;
|
||||||
width: 3px;
|
width: 4px;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.invalid {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
import { computed } from '@recore/obx';
|
import { computed, observer } from '@ali/lowcode-globals';
|
||||||
import { observer } from '@recore/obx-react';
|
|
||||||
import { SimulatorContext } from '../context';
|
import { SimulatorContext } from '../context';
|
||||||
import { SimulatorHost } from '../host';
|
import { BuiltinSimulatorHost } from '../host';
|
||||||
import Location, {
|
import {
|
||||||
|
DropLocation,
|
||||||
Rect,
|
Rect,
|
||||||
isLocationChildrenDetail,
|
isLocationChildrenDetail,
|
||||||
LocationChildrenDetail,
|
LocationChildrenDetail,
|
||||||
isVertical,
|
isVertical
|
||||||
} from '../../../../designer/helper/location';
|
} from '../../designer';
|
||||||
import { ISimulator } from '../../../../designer/simulator';
|
import { ISimulatorHost, } from '../../simulator';
|
||||||
import { NodeParent } from '../../../../designer/document/node/node';
|
import {NodeParent } from '../../document';
|
||||||
import './insertion.less';
|
import './insertion.less';
|
||||||
|
|
||||||
interface InsertionData {
|
interface InsertionData {
|
||||||
@ -24,15 +24,14 @@ interface InsertionData {
|
|||||||
/**
|
/**
|
||||||
* 处理拖拽子节点(INode)情况
|
* 处理拖拽子节点(INode)情况
|
||||||
*/
|
*/
|
||||||
function processChildrenDetail(sim: ISimulator, target: NodeParent, detail: LocationChildrenDetail): InsertionData {
|
function processChildrenDetail(sim: ISimulatorHost, container: NodeParent, detail: LocationChildrenDetail): InsertionData {
|
||||||
let edge = detail.edge || null;
|
let edge = detail.edge || null;
|
||||||
|
|
||||||
if (edge) {
|
|
||||||
edge = sim.computeRect(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!edge) {
|
if (!edge) {
|
||||||
return {};
|
edge = sim.computeRect(container);
|
||||||
|
if (!edge) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret: any = {
|
const ret: any = {
|
||||||
@ -43,18 +42,33 @@ function processChildrenDetail(sim: ISimulator, target: NodeParent, detail: Loca
|
|||||||
if (detail.near) {
|
if (detail.near) {
|
||||||
const { node, pos, rect, align } = detail.near;
|
const { node, pos, rect, align } = detail.near;
|
||||||
ret.nearRect = rect || sim.computeRect(node);
|
ret.nearRect = rect || sim.computeRect(node);
|
||||||
ret.vertical = align ? align === 'V' : isVertical(ret.nearRect);
|
if (pos === 'replace') {
|
||||||
ret.insertType = pos;
|
// FIXME: ret.nearRect mybe null
|
||||||
|
ret.coverRect = ret.nearRect;
|
||||||
|
ret.insertType = 'cover';
|
||||||
|
} else if (!ret.nearRect || (ret.nearRect.width === 0 && ret.nearRect.height === 0)) {
|
||||||
|
ret.nearRect = ret.edge;
|
||||||
|
ret.insertType = 'after';
|
||||||
|
ret.vertical = isVertical(ret.nearRect);
|
||||||
|
} else {
|
||||||
|
ret.insertType = pos;
|
||||||
|
ret.vertical = align ? align === 'V' : isVertical(ret.nearRect);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// from outline-tree: has index, but no near
|
// from outline-tree: has index, but no near
|
||||||
// TODO: think of shadowNode & ConditionFlow
|
// TODO: think of shadowNode & ConditionFlow
|
||||||
const { index } = detail;
|
const { index } = detail;
|
||||||
let nearNode = target.children.get(index);
|
if (index == null) {
|
||||||
|
ret.coverRect = ret.edge;
|
||||||
|
ret.insertType = 'cover';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
let nearNode = container.children.get(index);
|
||||||
if (!nearNode) {
|
if (!nearNode) {
|
||||||
// index = 0, eg. nochild,
|
// index = 0, eg. nochild,
|
||||||
nearNode = target.children.get(index > 0 ? index - 1 : 0);
|
nearNode = container.children.get(index > 0 ? index - 1 : 0);
|
||||||
if (!nearNode) {
|
if (!nearNode) {
|
||||||
ret.insertType = 'cover';
|
ret.insertType = 'cover';
|
||||||
ret.coverRect = edge;
|
ret.coverRect = edge;
|
||||||
@ -64,7 +78,14 @@ function processChildrenDetail(sim: ISimulator, target: NodeParent, detail: Loca
|
|||||||
}
|
}
|
||||||
if (nearNode) {
|
if (nearNode) {
|
||||||
ret.nearRect = sim.computeRect(nearNode);
|
ret.nearRect = sim.computeRect(nearNode);
|
||||||
|
if (!ret.nearRect || (ret.nearRect.width === 0 && ret.nearRect.height === 0)) {
|
||||||
|
ret.nearRect = ret.edge;
|
||||||
|
ret.insertType = 'after';
|
||||||
|
}
|
||||||
ret.vertical = isVertical(ret.nearRect);
|
ret.vertical = isVertical(ret.nearRect);
|
||||||
|
} else {
|
||||||
|
ret.insertType = 'cover';
|
||||||
|
ret.coverRect = edge;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -72,7 +93,7 @@ function processChildrenDetail(sim: ISimulator, target: NodeParent, detail: Loca
|
|||||||
/**
|
/**
|
||||||
* 将 detail 信息转换为页面"坐标"信息
|
* 将 detail 信息转换为页面"坐标"信息
|
||||||
*/
|
*/
|
||||||
function processDetail({ target, detail, document }: Location): InsertionData {
|
function processDetail({ target, detail, document }: DropLocation): InsertionData {
|
||||||
const sim = document.simulator;
|
const sim = document.simulator;
|
||||||
if (!sim) {
|
if (!sim) {
|
||||||
return {};
|
return {};
|
||||||
@ -85,7 +106,7 @@ function processDetail({ target, detail, document }: Location): InsertionData {
|
|||||||
if (!instances) {
|
if (!instances) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const edge = sim.computeComponentInstanceRect(instances[0]);
|
const edge = sim.computeComponentInstanceRect(instances[0], target.componentMeta.rectSelector);
|
||||||
return edge ? { edge, insertType: 'cover', coverRect: edge } : {};
|
return edge ? { edge, insertType: 'cover', coverRect: edge } : {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +115,7 @@ function processDetail({ target, detail, document }: Location): InsertionData {
|
|||||||
export class InsertionView extends Component {
|
export class InsertionView extends Component {
|
||||||
static contextType = SimulatorContext;
|
static contextType = SimulatorContext;
|
||||||
|
|
||||||
@computed get host(): SimulatorHost {
|
@computed get host(): BuiltinSimulatorHost {
|
||||||
return this.context;
|
return this.context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +137,9 @@ export class InsertionView extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let className = 'lc-insertion';
|
let className = 'lc-insertion';
|
||||||
|
if ((loc.detail as any)?.valid === false) {
|
||||||
|
className += ' invalid';
|
||||||
|
}
|
||||||
const style: any = {};
|
const style: any = {};
|
||||||
let x: number;
|
let x: number;
|
||||||
let y: number;
|
let y: number;
|
||||||
4
packages/designer/src/builtin-simulator/context.ts
Normal file
4
packages/designer/src/builtin-simulator/context.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
import { BuiltinSimulatorHost } from './host';
|
||||||
|
|
||||||
|
export const SimulatorContext = createContext<BuiltinSimulatorHost>({} as any);
|
||||||
@ -1,14 +1,14 @@
|
|||||||
// NOTE: 仅用作类型标注,切勿作为实体使用
|
// NOTE: 仅用作类型标注,切勿作为实体使用
|
||||||
import { SimulatorRenderer } from '../renderer/renderer';
|
import { BuiltinSimulatorHost } from './host';
|
||||||
import { SimulatorHost } from './host';
|
import { AssetLevel, AssetLevels, AssetList, isAssetBundle, isAssetItem, AssetType, assetItem } from '@ali/lowcode-globals';
|
||||||
import { AssetLevel, AssetLevels, AssetList, isAssetBundle, isAssetItem, AssetType, assetItem } from '../utils/asset';
|
import { isCSSUrl } from '@ali/lowcode-globals';
|
||||||
import { isCSSUrl } from '../../../utils/is-css-url';
|
import { BuiltinSimulatorRenderer } from './renderer';
|
||||||
|
|
||||||
export function createSimulator(
|
export function createSimulator(
|
||||||
host: SimulatorHost,
|
host: BuiltinSimulatorHost,
|
||||||
iframe: HTMLIFrameElement,
|
iframe: HTMLIFrameElement,
|
||||||
vendors: AssetList = [],
|
vendors: AssetList = [],
|
||||||
): Promise<SimulatorRenderer> {
|
): Promise<BuiltinSimulatorRenderer> {
|
||||||
const win: any = iframe.contentWindow;
|
const win: any = iframe.contentWindow;
|
||||||
const doc = iframe.contentDocument!;
|
const doc = iframe.contentDocument!;
|
||||||
|
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
import { observer } from '@recore/obx-react';
|
import { observer } from '@ali/lowcode-globals';
|
||||||
import { SimulatorHost, SimulatorProps } from './host';
|
import { BuiltinSimulatorHost, BuiltinSimulatorProps } from './host';
|
||||||
import DocumentModel from '../../../designer/document/document-model';
|
import { DocumentModel } from '../document';
|
||||||
import { SimulatorContext } from './context';
|
import { SimulatorContext } from './context';
|
||||||
import { AuxiliaryView } from './auxilary';
|
import { BemTools } from './bem-tools';
|
||||||
import './host.less';
|
import './host.less';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -15,20 +15,20 @@ import './host.less';
|
|||||||
Auxiliary 辅助显示层,初始相对 Content 位置 0,0,紧贴 Canvas, 根据 Content 滚动位置,改变相对位置
|
Auxiliary 辅助显示层,初始相对 Content 位置 0,0,紧贴 Canvas, 根据 Content 滚动位置,改变相对位置
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type SimulatorHostProps = SimulatorProps & {
|
type SimulatorHostProps = BuiltinSimulatorProps & {
|
||||||
documentContext: DocumentModel;
|
documentContext: DocumentModel;
|
||||||
onMount?: (host: SimulatorHost) => void;
|
onMount?: (host: BuiltinSimulatorHost) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class SimulatorHostView extends Component<SimulatorHostProps> {
|
export class BuiltinSimulatorHostView extends Component<SimulatorHostProps> {
|
||||||
readonly host: SimulatorHost;
|
readonly host: BuiltinSimulatorHost;
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
const { documentContext } = this.props;
|
const { documentContext } = this.props;
|
||||||
this.host = (documentContext.simulator as SimulatorHost) || new SimulatorHost(documentContext);
|
this.host = (documentContext.simulator as BuiltinSimulatorHost) || new BuiltinSimulatorHost(documentContext);
|
||||||
this.host.setProps(this.props);
|
this.host.setProps(this.props);
|
||||||
}
|
}
|
||||||
shouldComponentUpdate(nextProps: SimulatorProps) {
|
shouldComponentUpdate(nextProps: BuiltinSimulatorProps) {
|
||||||
this.host.setProps(nextProps);
|
this.host.setProps(nextProps);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ export class SimulatorHostView extends Component<SimulatorHostProps> {
|
|||||||
class Canvas extends Component {
|
class Canvas extends Component {
|
||||||
static contextType = SimulatorContext;
|
static contextType = SimulatorContext;
|
||||||
render() {
|
render() {
|
||||||
const sim = this.context as SimulatorHost;
|
const sim = this.context as BuiltinSimulatorHost;
|
||||||
let className = 'lc-simulator-canvas';
|
let className = 'lc-simulator-canvas';
|
||||||
if (sim.deviceClassName) {
|
if (sim.deviceClassName) {
|
||||||
className += ` ${sim.deviceClassName}`;
|
className += ` ${sim.deviceClassName}`;
|
||||||
@ -65,7 +65,7 @@ class Canvas extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<div ref={elmt => sim.mountViewport(elmt)} className="lc-simulator-canvas-viewport">
|
<div ref={elmt => sim.mountViewport(elmt)} className="lc-simulator-canvas-viewport">
|
||||||
<AuxiliaryView />
|
<BemTools />
|
||||||
<Content />
|
<Content />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -77,7 +77,7 @@ class Canvas extends Component {
|
|||||||
class Content extends Component {
|
class Content extends Component {
|
||||||
static contextType = SimulatorContext;
|
static contextType = SimulatorContext;
|
||||||
render() {
|
render() {
|
||||||
const sim = this.context as SimulatorHost;
|
const sim = this.context as BuiltinSimulatorHost;
|
||||||
const viewport = sim.viewport;
|
const viewport = sim.viewport;
|
||||||
let frameStyle = {};
|
let frameStyle = {};
|
||||||
if (viewport.scale < 1) {
|
if (viewport.scale < 1) {
|
||||||
@ -1,23 +1,16 @@
|
|||||||
import { obx, autorun, computed } from '@recore/obx';
|
import { obx, autorun, computed } from '@ali/lowcode-globals';
|
||||||
import { ISimulator, Component, NodeInstance } from '../../../designer/simulator';
|
import { ISimulatorHost, Component, NodeInstance, ComponentInstance } from '../simulator';
|
||||||
import Viewport from './viewport';
|
import Viewport from './viewport';
|
||||||
import { createSimulator } from './create-simulator';
|
import { createSimulator } from './create-simulator';
|
||||||
import { SimulatorRenderer } from '../renderer/renderer';
|
import { Node, NodeParent, DocumentModel, isNodeParent, isNode, contains, isRootNode } from '../document';
|
||||||
import Node, { NodeParent, isNodeParent, isNode, contains } from '../../../designer/document/node/node';
|
|
||||||
import DocumentModel from '../../../designer/document/document-model';
|
|
||||||
import ResourceConsumer from './resource-consumer';
|
import ResourceConsumer from './resource-consumer';
|
||||||
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType } from '../utils/asset';
|
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType, getPublicPath } from '@ali/lowcode-globals';
|
||||||
import {
|
import {
|
||||||
DragObjectType,
|
DragObjectType,
|
||||||
isShaken,
|
isShaken,
|
||||||
LocateEvent,
|
LocateEvent,
|
||||||
DragNodeObject,
|
|
||||||
DragNodeDataObject,
|
|
||||||
isDragAnyObject,
|
isDragAnyObject,
|
||||||
isDragNodeObject,
|
isDragNodeObject,
|
||||||
isDragNodeDataObject,
|
|
||||||
} from '../../../designer/helper/dragon';
|
|
||||||
import {
|
|
||||||
LocationData,
|
LocationData,
|
||||||
isLocationData,
|
isLocationData,
|
||||||
LocationChildrenDetail,
|
LocationChildrenDetail,
|
||||||
@ -27,12 +20,13 @@ import {
|
|||||||
getRectTarget,
|
getRectTarget,
|
||||||
Rect,
|
Rect,
|
||||||
CanvasPoint,
|
CanvasPoint,
|
||||||
} from '../../../designer/helper/location';
|
hotkey,
|
||||||
import { isNodeSchema, NodeSchema } from '../../../designer/schema';
|
} from '../designer';
|
||||||
import { ComponentMetadata } from '../../../designer/component-meta';
|
import { parseProps } from './utils/parse-props';
|
||||||
import { ReactInstance } from 'react';
|
import { isElement } from '@ali/lowcode-globals';
|
||||||
import { isRootNode } from '../../../designer/document/node/root-node';
|
import { ComponentMetadata } from '@ali/lowcode-globals';
|
||||||
import { parseProps } from '../utils/parse-props';
|
import { BuiltinSimulatorRenderer } from './renderer';
|
||||||
|
import clipboard from '../designer/clipboard';
|
||||||
|
|
||||||
export interface LibraryItem {
|
export interface LibraryItem {
|
||||||
package: string;
|
package: string;
|
||||||
@ -40,7 +34,7 @@ export interface LibraryItem {
|
|||||||
urls: Asset;
|
urls: Asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimulatorProps {
|
export interface BuiltinSimulatorProps {
|
||||||
// 从 documentModel 上获取
|
// 从 documentModel 上获取
|
||||||
// suspended?: boolean;
|
// suspended?: boolean;
|
||||||
designMode?: 'live' | 'design' | 'mock' | 'extend' | 'border' | 'preview';
|
designMode?: 'live' | 'design' | 'mock' | 'extend' | 'border' | 'preview';
|
||||||
@ -54,14 +48,16 @@ export interface SimulatorProps {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const publicPath = (document.currentScript as HTMLScriptElement).src.replace(/^(.*\/)[^/]+$/, '$1');
|
|
||||||
|
|
||||||
const defaultSimulatorUrl = (() => {
|
const defaultSimulatorUrl = (() => {
|
||||||
|
const publicPath = getPublicPath();
|
||||||
let urls;
|
let urls;
|
||||||
if (process.env.NODE_ENV === 'production') {
|
const [_, prefix = '', dev] = /^(.+?)(\/js)?\/?$/.exec(publicPath) || [];
|
||||||
urls = [`${publicPath}../css/simulator-renderer.min.css`, `${publicPath}simulator-renderer.min.js`];
|
if (dev) {
|
||||||
|
urls = [`${prefix}/css/react-simulator-renderer.css`, `${prefix}/js/react-simulator-renderer.js`];
|
||||||
|
} else if (process.env.NODE_ENV === 'production') {
|
||||||
|
urls = [`${prefix}/react-simulator-renderer.min.css`, `${prefix}/react-simulator-renderer.min.js`];
|
||||||
} else {
|
} else {
|
||||||
urls = [`${publicPath}../css/simulator-renderer.css`, `${publicPath}simulator-renderer.js`];
|
urls = [`${prefix}/react-simulator-renderer.css`, `${prefix}/react-simulator-renderer.js`];
|
||||||
}
|
}
|
||||||
return urls;
|
return urls;
|
||||||
})();
|
})();
|
||||||
@ -73,10 +69,9 @@ const defaultEnvironment = [
|
|||||||
AssetType.JSText,
|
AssetType.JSText,
|
||||||
'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
|
'window.PropTypes=parent.PropTypes;React.PropTypes=parent.PropTypes; window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__;',
|
||||||
),
|
),
|
||||||
assetItem(AssetType.JSUrl, '/statics/lowcode-renderer.js'),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export class SimulatorHost implements ISimulator<SimulatorProps> {
|
export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProps> {
|
||||||
readonly isSimulator = true;
|
readonly isSimulator = true;
|
||||||
|
|
||||||
constructor(readonly document: DocumentModel) {}
|
constructor(readonly document: DocumentModel) {}
|
||||||
@ -112,11 +107,11 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
return this.designer.componentsMap;
|
return this.designer.componentsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@obx.ref _props: SimulatorProps = {};
|
@obx.ref _props: BuiltinSimulatorProps = {};
|
||||||
/**
|
/**
|
||||||
* @see ISimulator
|
* @see ISimulator
|
||||||
*/
|
*/
|
||||||
setProps(props: SimulatorProps) {
|
setProps(props: BuiltinSimulatorProps) {
|
||||||
this._props = props;
|
this._props = props;
|
||||||
}
|
}
|
||||||
set(key: string, value: any) {
|
set(key: string, value: any) {
|
||||||
@ -132,7 +127,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
/**
|
/**
|
||||||
* 有 Renderer 进程连接进来,设置同步机制
|
* 有 Renderer 进程连接进来,设置同步机制
|
||||||
*/
|
*/
|
||||||
connect(renderer: SimulatorRenderer, fn: (context: { dispose: () => void; firstRun: boolean }) => void) {
|
connect(renderer: BuiltinSimulatorRenderer, fn: (context: { dispose: () => void; firstRun: boolean }) => void) {
|
||||||
this._renderer = renderer;
|
this._renderer = renderer;
|
||||||
return autorun(fn as any, true);
|
return autorun(fn as any, true);
|
||||||
}
|
}
|
||||||
@ -158,7 +153,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
return this._contentDocument;
|
return this._contentDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderer?: SimulatorRenderer;
|
private _renderer?: BuiltinSimulatorRenderer;
|
||||||
get renderer() {
|
get renderer() {
|
||||||
return this._renderer;
|
return this._renderer;
|
||||||
}
|
}
|
||||||
@ -183,7 +178,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
const library = this.get('library') as LibraryItem[];
|
const library = this.get('library') as LibraryItem[];
|
||||||
const libraryAsset: AssetList = [];
|
const libraryAsset: AssetList = [];
|
||||||
if (library) {
|
if (library) {
|
||||||
library.forEach(item => {
|
library.forEach((item) => {
|
||||||
this.libraryMap[item.package] = item.library;
|
this.libraryMap[item.package] = item.library;
|
||||||
libraryAsset.push(item.urls);
|
libraryAsset.push(item.urls);
|
||||||
});
|
});
|
||||||
@ -203,6 +198,8 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
// wait 准备 iframe 内容、依赖库注入
|
// wait 准备 iframe 内容、依赖库注入
|
||||||
const renderer = await createSimulator(this, iframe, vendors);
|
const renderer = await createSimulator(this, iframe, vendors);
|
||||||
|
|
||||||
|
// TODO: !!! thinkof reload onload
|
||||||
|
|
||||||
// wait 业务组件被第一次消费,否则会渲染出错
|
// wait 业务组件被第一次消费,否则会渲染出错
|
||||||
await this.componentsConsumer.waitFirstConsume();
|
await this.componentsConsumer.waitFirstConsume();
|
||||||
|
|
||||||
@ -216,11 +213,17 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
this._contentDocument = this._contentWindow.document;
|
this._contentDocument = this._contentWindow.document;
|
||||||
this.viewport.setScrollTarget(this._contentWindow);
|
this.viewport.setScrollTarget(this._contentWindow);
|
||||||
this.setupEvents();
|
this.setupEvents();
|
||||||
// hotkey.mount(this.contentWindow);
|
|
||||||
// clipboard.injectCopyPaster(this.ownerDocument);
|
// bind hotkey & clipboard
|
||||||
|
hotkey.mount(this._contentWindow);
|
||||||
|
clipboard.injectCopyPaster(this._contentDocument);
|
||||||
|
// TODO: dispose the bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
setupEvents() {
|
setupEvents() {
|
||||||
|
// TODO: Thinkof move events control to simulator renderer
|
||||||
|
// just listen special callback
|
||||||
|
// because iframe maybe reload
|
||||||
this.setupDragAndClick();
|
this.setupDragAndClick();
|
||||||
this.setupHovering();
|
this.setupHovering();
|
||||||
}
|
}
|
||||||
@ -295,7 +298,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
|
|
||||||
doc.addEventListener(
|
doc.addEventListener(
|
||||||
'click',
|
'click',
|
||||||
e => {
|
(e) => {
|
||||||
// stop response document click event
|
// stop response document click event
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -405,8 +408,8 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
return this.renderer?.getComponent(componentName) || null;
|
return this.renderer?.getComponent(componentName) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@obx.val private instancesMap = new Map<string, ReactInstance[]>();
|
@obx.val private instancesMap = new Map<string, ComponentInstance[]>();
|
||||||
setInstance(id: string, instances: ReactInstance[] | null) {
|
setInstance(id: string, instances: ComponentInstance[] | null) {
|
||||||
if (instances == null) {
|
if (instances == null) {
|
||||||
this.instancesMap.delete(id);
|
this.instancesMap.delete(id);
|
||||||
} else {
|
} else {
|
||||||
@ -417,14 +420,14 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
/**
|
/**
|
||||||
* @see ISimulator
|
* @see ISimulator
|
||||||
*/
|
*/
|
||||||
getComponentInstances(node: Node): ReactInstance[] | null {
|
getComponentInstances(node: Node): ComponentInstance[] | null {
|
||||||
return this.instancesMap.get(node.id) || null;
|
return this.instancesMap.get(node.id) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ISimulator
|
* @see ISimulator
|
||||||
*/
|
*/
|
||||||
getComponentInstanceId(instance: ReactInstance) {
|
getComponentInstanceId(instance: ComponentInstance) {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +441,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
/**
|
/**
|
||||||
* @see ISimulator
|
* @see ISimulator
|
||||||
*/
|
*/
|
||||||
getClosestNodeInstance(from: ReactInstance, specId?: string): NodeInstance<ReactInstance> | null {
|
getClosestNodeInstance(from: ComponentInstance, specId?: string): NodeInstance<ComponentInstance> | null {
|
||||||
return this.renderer?.getClosestNodeInstance(from, specId) || null;
|
return this.renderer?.getClosestNodeInstance(from, specId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,36 +453,36 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
if (!instances) {
|
if (!instances) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.computeComponentInstanceRect(instances[0]);
|
return this.computeComponentInstanceRect(instances[0], node.componentMeta.rectSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ISimulator
|
* @see ISimulator
|
||||||
*/
|
*/
|
||||||
computeComponentInstanceRect(instance: ReactInstance): Rect | null {
|
computeComponentInstanceRect(instance: ComponentInstance, selector?: string): Rect | null {
|
||||||
const renderer = this.renderer!;
|
const renderer = this.renderer!;
|
||||||
const elements = renderer.findDOMNodes(instance);
|
const elements = renderer.findDOMNodes(instance);
|
||||||
if (!elements) {
|
if (!elements) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let elems = elements.slice();
|
||||||
|
if (selector) {
|
||||||
|
const matched = getMatched(elems, selector);
|
||||||
|
if (!matched) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
elems = [matched];
|
||||||
|
}
|
||||||
let rects: DOMRect[] | undefined;
|
let rects: DOMRect[] | undefined;
|
||||||
let last: { x: number; y: number; r: number; b: number } | undefined;
|
let last: { x: number; y: number; r: number; b: number } | undefined;
|
||||||
let computed = false;
|
let computed = false;
|
||||||
const elems = elements.slice();
|
|
||||||
const commonParent: Element | null = null;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!rects || rects.length < 1) {
|
if (!rects || rects.length < 1) {
|
||||||
const elem = elems.pop();
|
const elem = elems.pop();
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if (!commonParent) {
|
|
||||||
commonParent = elem.parentElement;
|
|
||||||
} else if (elem.parentElement !== commonParent) {
|
|
||||||
continue;
|
|
||||||
}*/
|
|
||||||
rects = renderer.getClientRects(elem);
|
rects = renderer.getClientRects(elem);
|
||||||
}
|
}
|
||||||
const rect = rects.pop();
|
const rect = rects.pop();
|
||||||
@ -529,14 +532,14 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
/**
|
/**
|
||||||
* @see ISimulator
|
* @see ISimulator
|
||||||
*/
|
*/
|
||||||
findDOMNodes(instance: ReactInstance): Array<Element | Text> | null {
|
findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null {
|
||||||
return this._renderer?.findDOMNodes(instance) || null;
|
return this._renderer?.findDOMNodes(instance) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过 DOM 节点获取节点,依赖 simulator 的接口
|
* 通过 DOM 节点获取节点,依赖 simulator 的接口
|
||||||
*/
|
*/
|
||||||
getNodeInstanceFromElement(target: Element | null): NodeInstance | null {
|
getNodeInstanceFromElement(target: Element | null): NodeInstance<ComponentInstance> | null {
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -701,28 +704,24 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
locate(e: LocateEvent): any {
|
locate(e: LocateEvent): any {
|
||||||
this.sensing = true;
|
this.sensing = true;
|
||||||
this.scroller.scrolling(e);
|
this.scroller.scrolling(e);
|
||||||
const dropTarget = this.getDropTarget(e);
|
const dropContainer = this.getDropContainer(e);
|
||||||
if (!dropTarget) {
|
if (!dropContainer) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLocationData(dropTarget)) {
|
if (isLocationData(dropContainer)) {
|
||||||
return this.designer.createLocation(dropTarget);
|
return this.designer.createLocation(dropContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const target = dropTarget;
|
const { container, instance: containerInstance } = dropContainer;
|
||||||
|
|
||||||
// FIXME: e.target is #document, etc., does not has e.targetInstance
|
const edge = this.computeComponentInstanceRect(containerInstance, container.componentMeta.rectSelector);
|
||||||
|
|
||||||
const targetInstance = e.targetInstance as ReactInstance;
|
|
||||||
const parentInstance = this.getClosestNodeInstance(targetInstance, target.id);
|
|
||||||
const edge = this.computeComponentInstanceRect(parentInstance?.instance as any);
|
|
||||||
|
|
||||||
if (!edge) {
|
if (!edge) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const children = target.children;
|
const children = container.children;
|
||||||
|
|
||||||
const detail: LocationChildrenDetail = {
|
const detail: LocationChildrenDetail = {
|
||||||
type: LocationDetailType.Children,
|
type: LocationDetailType.Children,
|
||||||
@ -731,8 +730,10 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const locationData = {
|
const locationData = {
|
||||||
target,
|
target: container,
|
||||||
detail,
|
detail,
|
||||||
|
source: 'simulator' + this.document.id,
|
||||||
|
event: e,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!children || children.size < 1 || !edge) {
|
if (!children || children.size < 1 || !edge) {
|
||||||
@ -752,10 +753,10 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
const instances = this.getComponentInstances(node);
|
const instances = this.getComponentInstances(node);
|
||||||
const inst = instances
|
const inst = instances
|
||||||
? instances.length > 1
|
? instances.length > 1
|
||||||
? instances.find(inst => this.getClosestNodeInstance(inst, target.id)?.instance === targetInstance)
|
? instances.find((inst) => this.getClosestNodeInstance(inst, container.id)?.instance === containerInstance)
|
||||||
: instances[0]
|
: instances[0]
|
||||||
: null;
|
: null;
|
||||||
const rect = inst ? this.computeComponentInstanceRect(inst) : null;
|
const rect = inst ? this.computeComponentInstanceRect(inst, node.componentMeta.rectSelector) : null;
|
||||||
|
|
||||||
if (!rect) {
|
if (!rect) {
|
||||||
continue;
|
continue;
|
||||||
@ -795,6 +796,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
const inline = el ? isChildInline(el) : false;
|
const inline = el ? isChildInline(el) : false;
|
||||||
const row = el ? isRowContainer(el.parentElement!) : false;
|
const row = el ? isRowContainer(el.parentElement!) : false;
|
||||||
const vertical = inline || row;
|
const vertical = inline || row;
|
||||||
|
|
||||||
// TODO: fix type
|
// TODO: fix type
|
||||||
const near: any = {
|
const near: any = {
|
||||||
node: nearNode,
|
node: nearNode,
|
||||||
@ -827,61 +829,109 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
return this.designer.createLocation(locationData);
|
return this.designer.createLocation(locationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDropTarget(e: LocateEvent): NodeParent | LocationData | null {
|
/**
|
||||||
|
* 查找合适的投放容器
|
||||||
|
*/
|
||||||
|
getDropContainer(e: LocateEvent): DropContainer | LocationData | null {
|
||||||
const { target, dragObject } = e;
|
const { target, dragObject } = e;
|
||||||
const isAny = isDragAnyObject(dragObject);
|
const isAny = isDragAnyObject(dragObject);
|
||||||
let container: any;
|
const { modalNode, currentRoot } = this.document;
|
||||||
|
let container: Node;
|
||||||
|
let nodeInstance: NodeInstance<ComponentInstance> | undefined;
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
const ref = this.getNodeInstanceFromElement(target);
|
const ref = this.getNodeInstanceFromElement(target);
|
||||||
if (ref?.node) {
|
if (ref?.node) {
|
||||||
e.targetInstance = ref.instance;
|
nodeInstance = ref;
|
||||||
e.targetNode = ref.node;
|
|
||||||
container = ref.node;
|
container = ref.node;
|
||||||
} else if (isAny) {
|
} else if (isAny) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
container = this.document.rootNode;
|
container = currentRoot;
|
||||||
}
|
}
|
||||||
} else if (isAny) {
|
} else if (isAny) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
container = this.document.rootNode;
|
container = currentRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNodeParent(container) && !isRootNode(container)) {
|
if (!isNodeParent(container)) {
|
||||||
container = container.parent;
|
container = container.parent || currentRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check container if in modalNode layer, if not, use modalNode
|
||||||
|
if (modalNode && !modalNode.contains(container)) {
|
||||||
|
container = modalNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use spec container to accept specialData
|
||||||
if (isAny) {
|
if (isAny) {
|
||||||
// TODO: use spec container to accept specialData
|
// will return locationData
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get common parent, avoid drop container contains by dragObject
|
||||||
|
// TODO: renderengine support pointerEvents: none for acceleration
|
||||||
|
const drillDownExcludes = new Set<Node>();
|
||||||
|
if (isDragNodeObject(dragObject)) {
|
||||||
|
const nodes = dragObject.nodes;
|
||||||
|
let i = nodes.length;
|
||||||
|
let p: any = container;
|
||||||
|
while (i-- > 0) {
|
||||||
|
if (contains(nodes[i], p)) {
|
||||||
|
p = nodes[i].parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p !== container) {
|
||||||
|
container = p || this.document.rootNode;
|
||||||
|
drillDownExcludes.add(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ret: any = {
|
||||||
|
container,
|
||||||
|
};
|
||||||
|
if (nodeInstance) {
|
||||||
|
if (nodeInstance.node === container) {
|
||||||
|
ret.instance = nodeInstance.instance;
|
||||||
|
} else {
|
||||||
|
ret.instance = this.getClosestNodeInstance(nodeInstance.instance as any, container.id)?.instance;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret.instance = this.getComponentInstances(container)?.[0];
|
||||||
|
}
|
||||||
|
|
||||||
let res: any;
|
let res: any;
|
||||||
let upward: any;
|
let upward: any;
|
||||||
// TODO: improve AT_CHILD logic, mark has checked
|
// TODO: complete drill down logic
|
||||||
while (container) {
|
while (container) {
|
||||||
res = this.acceptNodes(container, e);
|
if (ret.container !== container) {
|
||||||
|
ret.container = container;
|
||||||
|
ret.instance = this.getClosestNodeInstance(ret.instance, container.id)?.instance;
|
||||||
|
}
|
||||||
|
res = this.handleAccept(ret, e);
|
||||||
if (isLocationData(res)) {
|
if (isLocationData(res)) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (res === true) {
|
if (res === true) {
|
||||||
return container;
|
return ret;
|
||||||
}
|
}
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
drillDownExcludes.add(container);
|
||||||
if (upward) {
|
if (upward) {
|
||||||
container = upward;
|
container = upward;
|
||||||
upward = null;
|
upward = null;
|
||||||
} else {
|
} else if (container.parent) {
|
||||||
container = container.parent;
|
container = container.parent;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
} else if (isNode(res)) {
|
} else if (isNode(res)) {
|
||||||
/* else if (res === AT_CHILD) {
|
/* else if (res === DRILL_DOWN) {
|
||||||
if (!upward) {
|
if (!upward) {
|
||||||
upward = container.parent;
|
upward = container.parent;
|
||||||
}
|
}
|
||||||
container = this.getNearByContainer(container, e);
|
container = this.getNearByContainer(container, drillExcludes, e);
|
||||||
if (!container) {
|
if (!container) {
|
||||||
container = upward;
|
container = upward;
|
||||||
upward = null;
|
upward = null;
|
||||||
@ -894,38 +944,71 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptNodes(container: NodeParent, e: LocateEvent) {
|
isAcceptable(container: NodeParent): boolean {
|
||||||
const { dragObject } = e;
|
return false;
|
||||||
if (isRootNode(container)) {
|
/*
|
||||||
return this.checkDropTarget(container, dragObject as any);
|
const meta = container.componentMeta;
|
||||||
|
const instance: any = this.document.getView(container);
|
||||||
|
if (instance && '$accept' in instance) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return meta.acceptable;
|
||||||
const config = container.componentMeta;
|
*/
|
||||||
|
|
||||||
if (!config.isContainer) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// check is contains, get common parent
|
|
||||||
if (isDragNodeObject(dragObject)) {
|
|
||||||
const nodes = dragObject.nodes;
|
|
||||||
let i = nodes.length;
|
|
||||||
let p: any = container;
|
|
||||||
while (i-- > 0) {
|
|
||||||
if (contains(nodes[i], p)) {
|
|
||||||
p = nodes[i].parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p !== container) {
|
|
||||||
return p || this.document.rootNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.checkNesting(container, dragObject as any);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
getNearByContainer(container: NodeParent, e: LocateEvent) {
|
* 控制接受
|
||||||
|
*/
|
||||||
|
handleAccept({ container, instance }: DropContainer, e: LocateEvent) {
|
||||||
|
const { dragObject } = e;
|
||||||
|
if (isRootNode(container)) {
|
||||||
|
return this.document.checkDropTarget(container, dragObject as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = container.componentMeta;
|
||||||
|
|
||||||
|
// FIXME: get containerInstance for accept logic use
|
||||||
|
const acceptable: boolean = this.isAcceptable(container);
|
||||||
|
if (!meta.isContainer && !acceptable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// first use accept
|
||||||
|
if (acceptable) {
|
||||||
|
/*
|
||||||
|
const view: any = this.document.getView(container);
|
||||||
|
if (view && '$accept' in view) {
|
||||||
|
if (view.$accept === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (view.$accept === AT_CHILD || view.$accept === '@CHILD') {
|
||||||
|
return AT_CHILD;
|
||||||
|
}
|
||||||
|
if (typeof view.$accept === 'function') {
|
||||||
|
const ret = view.$accept(container, e);
|
||||||
|
if (ret || ret === false) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (proto.acceptable) {
|
||||||
|
const ret = proto.accept(container, e);
|
||||||
|
if (ret || ret === false) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// check nesting
|
||||||
|
return this.document.checkNesting(container, dragObject as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找邻近容器
|
||||||
|
*/
|
||||||
|
getNearByContainer(container: NodeParent, e: LocateEvent) {
|
||||||
|
/*
|
||||||
const children = container.children;
|
const children = container.children;
|
||||||
if (!children || children.length < 1) {
|
if (!children || children.length < 1) {
|
||||||
return null;
|
return null;
|
||||||
@ -960,43 +1043,7 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nearBy;
|
return nearBy;
|
||||||
}
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
checkNesting(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
|
||||||
let items: Array<Node | NodeSchema>;
|
|
||||||
if (isDragNodeDataObject(dragObject)) {
|
|
||||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
|
||||||
} else {
|
|
||||||
items = dragObject.nodes;
|
|
||||||
}
|
|
||||||
return items.every(item => this.checkNestingDown(dropTarget, item));
|
|
||||||
}
|
|
||||||
|
|
||||||
checkDropTarget(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
|
||||||
let items: Array<Node | NodeSchema>;
|
|
||||||
if (isDragNodeDataObject(dragObject)) {
|
|
||||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
|
||||||
} else {
|
|
||||||
items = dragObject.nodes;
|
|
||||||
}
|
|
||||||
return items.every(item => this.checkNestingUp(dropTarget, item));
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNestingUp(parent: NodeParent, target: NodeSchema | Node): boolean {
|
|
||||||
if (isNode(target) || isNodeSchema(target)) {
|
|
||||||
const config = isNode(target) ? target.componentMeta : this.document.getComponentMeta(target.componentName);
|
|
||||||
if (config) {
|
|
||||||
return config.checkNestingUp(target, parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNestingDown(parent: NodeParent, target: NodeSchema | Node): boolean {
|
|
||||||
const config = parent.componentMeta;
|
|
||||||
return config.checkNestingDown(parent, target) && this.checkNestingUp(parent, target);
|
|
||||||
}
|
}
|
||||||
// #endregion
|
// #endregion
|
||||||
}
|
}
|
||||||
@ -1046,3 +1093,24 @@ function isNearAfter(point: CanvasPoint, rect: Rect, inline: boolean) {
|
|||||||
}
|
}
|
||||||
return Math.abs(point.canvasY - rect.top) > Math.abs(point.canvasY - rect.bottom);
|
return Math.abs(point.canvasY - rect.top) > Math.abs(point.canvasY - rect.bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMatched(elements: Array<Element | Text>, selector: string): Element | null {
|
||||||
|
let firstQueried: Element | null = null;
|
||||||
|
for (const elem of elements) {
|
||||||
|
if (isElement(elem)) {
|
||||||
|
if (elem.matches(selector)) {
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstQueried) {
|
||||||
|
firstQueried = elem.querySelector(selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return firstQueried;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DropContainer {
|
||||||
|
container: NodeParent;
|
||||||
|
instance: ComponentInstance;
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './host';
|
export * from './host';
|
||||||
export * from './host-view';
|
export * from './host-view';
|
||||||
|
export * from './renderer';
|
||||||
19
packages/designer/src/builtin-simulator/renderer.ts
Normal file
19
packages/designer/src/builtin-simulator/renderer.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { ComponentInstance, NodeInstance, Component } from '../simulator';
|
||||||
|
|
||||||
|
export interface BuiltinSimulatorRenderer {
|
||||||
|
readonly isSimulatorRenderer: true;
|
||||||
|
getComponent(componentName: string): Component;
|
||||||
|
getComponentInstances(id: string): ComponentInstance[] | null;
|
||||||
|
getClosestNodeInstance(from: ComponentInstance, nodeId?: string): NodeInstance<ComponentInstance> | null;
|
||||||
|
findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null;
|
||||||
|
getClientRects(element: Element | Text): DOMRect[];
|
||||||
|
setNativeSelection(enableFlag: boolean): void;
|
||||||
|
setDraggingState(state: boolean): void;
|
||||||
|
setCopyState(state: boolean): void;
|
||||||
|
clearState(): void;
|
||||||
|
run(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSimulatorRenderer(obj: any): obj is BuiltinSimulatorRenderer {
|
||||||
|
return obj && obj.isSimulatorRenderer;
|
||||||
|
}
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import { SimulatorRenderer } from '../renderer/renderer';
|
import { autorun, obx } from '@ali/lowcode-globals';
|
||||||
import { autorun, obx } from '@recore/obx';
|
import { BuiltinSimulatorHost } from './host';
|
||||||
import { SimulatorHost } from './host';
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
import { BuiltinSimulatorRenderer, isSimulatorRenderer } from './renderer';
|
||||||
|
|
||||||
const UNSET = Symbol('unset');
|
const UNSET = Symbol('unset');
|
||||||
export type MasterProvider = (master: SimulatorHost) => any;
|
export type MasterProvider = (master: BuiltinSimulatorHost) => any;
|
||||||
export type RendererConsumer<T> = (renderer: SimulatorRenderer, data: T) => Promise<any>;
|
export type RendererConsumer<T> = (renderer: BuiltinSimulatorRenderer, data: T) => Promise<any>;
|
||||||
|
|
||||||
// master 进程
|
// master 进程
|
||||||
// 0. 初始化该对象,因为需要响应变更发生在 master 进程
|
// 0. 初始化该对象,因为需要响应变更发生在 master 进程
|
||||||
@ -19,10 +19,6 @@ export type RendererConsumer<T> = (renderer: SimulatorRenderer, data: T) => Prom
|
|||||||
// 1. 被消费数据协议
|
// 1. 被消费数据协议
|
||||||
// 2. 消费机制(渲染进程自定 + 传递进入)
|
// 2. 消费机制(渲染进程自定 + 传递进入)
|
||||||
|
|
||||||
function isSimulatorRenderer(obj: any): obj is SimulatorRenderer {
|
|
||||||
return obj && obj.isSimulatorRenderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class ResourceConsumer<T = any> {
|
export default class ResourceConsumer<T = any> {
|
||||||
private emitter = new EventEmitter();
|
private emitter = new EventEmitter();
|
||||||
@obx.ref private _data: T | typeof UNSET = UNSET;
|
@obx.ref private _data: T | typeof UNSET = UNSET;
|
||||||
@ -34,9 +30,8 @@ export default class ResourceConsumer<T = any> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private _consuming?: () => void;
|
private _consuming?: () => void;
|
||||||
consume(consumerOrRenderer: SimulatorRenderer | ((data: T) => any)) {
|
consume(consumerOrRenderer: BuiltinSimulatorRenderer | ((data: T) => any)) {
|
||||||
if (this._consuming) {
|
if (this._consuming) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -48,7 +43,7 @@ export default class ResourceConsumer<T = any> {
|
|||||||
}
|
}
|
||||||
const rendererConsumer = this.consumer!;
|
const rendererConsumer = this.consumer!;
|
||||||
|
|
||||||
consumer = (data) => rendererConsumer(consumerOrRenderer, data);
|
consumer = data => rendererConsumer(consumerOrRenderer, data);
|
||||||
} else {
|
} else {
|
||||||
consumer = consumerOrRenderer;
|
consumer = consumerOrRenderer;
|
||||||
}
|
}
|
||||||
@ -76,14 +71,14 @@ export default class ResourceConsumer<T = any> {
|
|||||||
this.emitter.removeAllListeners();
|
this.emitter.removeAllListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _firstConsumed: boolean = false;
|
private _firstConsumed = false;
|
||||||
private resovleFirst?: () => void;
|
private resovleFirst?: () => void;
|
||||||
|
|
||||||
waitFirstConsume(): Promise<any> {
|
waitFirstConsume(): Promise<any> {
|
||||||
if (this._firstConsumed) {
|
if (this._firstConsumed) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return new Promise((resolve) => {
|
return new Promise(resolve => {
|
||||||
this.resovleFirst = resolve;
|
this.resovleFirst = resolve;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { isValidElement } from 'react';
|
import { isValidElement } from 'react';
|
||||||
import { isElement } from '../../../utils/is-element';
|
import { isElement } from '@ali/lowcode-globals';
|
||||||
import { PropType, PropConfig } from '../../../designer/prop-config';
|
import { PropConfig } from '@ali/lowcode-globals';
|
||||||
|
|
||||||
export const primitiveTypes = [
|
export const primitiveTypes = [
|
||||||
'string',
|
'string',
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import { obx, computed } from '@recore/obx';
|
import { obx, computed } from '@ali/lowcode-globals';
|
||||||
import { Point } from '../../../designer/helper/location';
|
import { Point, ScrollTarget } from '../designer';
|
||||||
import { ScrollTarget } from '../../../designer/helper/scroller';
|
import { AutoFit, IViewport } from '../simulator';
|
||||||
import { AutoFit, IViewport } from '../../../designer/simulator';
|
|
||||||
|
|
||||||
export default class Viewport implements IViewport {
|
export default class Viewport implements IViewport {
|
||||||
@obx.ref private rect?: DOMRect;
|
@obx.ref private rect?: DOMRect;
|
||||||
@ -1 +0,0 @@
|
|||||||
主进程
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
import { observer } from '@recore/obx-react';
|
|
||||||
import { Component } from 'react';
|
|
||||||
import { OutlineHovering } from './outline-hovering';
|
|
||||||
import { SimulatorContext } from '../context';
|
|
||||||
import { SimulatorHost } from '../host';
|
|
||||||
import { OutlineSelecting } from './outline-selecting';
|
|
||||||
import { InsertionView } from './insertion';
|
|
||||||
import './auxiliary.less';
|
|
||||||
import './outlines.less';
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class AuxiliaryView extends Component {
|
|
||||||
static contextType = SimulatorContext;
|
|
||||||
|
|
||||||
shouldComponentUpdate() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const host = this.context as SimulatorHost;
|
|
||||||
const { scrollX, scrollY, scale } = host.viewport;
|
|
||||||
return (
|
|
||||||
<div className="lc-auxiliary" style={{ transform: `translate(${-scrollX * scale}px,${-scrollY * scale}px)` }}>
|
|
||||||
<OutlineHovering key="hovering" />
|
|
||||||
<OutlineSelecting key="selecting" />
|
|
||||||
<InsertionView key="insertion" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
export * from './auxiliary';
|
|
||||||
@ -1,132 +0,0 @@
|
|||||||
import { Component, Fragment } from 'react';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { observer } from '@recore/obx-react';
|
|
||||||
import { SimulatorContext } from '../context';
|
|
||||||
import { SimulatorHost } from '../host';
|
|
||||||
import { computed } from '@recore/obx';
|
|
||||||
import OffsetObserver from '../../../../designer/helper/offset-observer';
|
|
||||||
import Node from '../../../../designer/document/node/node';
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class OutlineSelectingInstance extends Component<{
|
|
||||||
observed: OffsetObserver;
|
|
||||||
highlight?: boolean;
|
|
||||||
dragging?: boolean;
|
|
||||||
}> {
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.props.observed.purge();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { observed, highlight, dragging } = this.props;
|
|
||||||
if (!observed.hasOffset) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed;
|
|
||||||
|
|
||||||
const style = {
|
|
||||||
width: offsetWidth,
|
|
||||||
height: offsetHeight,
|
|
||||||
transform: `translate3d(${offsetLeft}px, ${offsetTop}px, 0)`,
|
|
||||||
};
|
|
||||||
|
|
||||||
const className = classNames('lc-outlines lc-outlines-selecting', {
|
|
||||||
highlight,
|
|
||||||
dragging,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={className} style={style}>
|
|
||||||
<a className="lc-outlines-title">{observed.nodeInstance.node.title}</a>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class OutlineSelectingForNode extends Component<{ node: Node }> {
|
|
||||||
static contextType = SimulatorContext;
|
|
||||||
|
|
||||||
get host(): SimulatorHost {
|
|
||||||
return this.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
get dragging(): boolean {
|
|
||||||
return this.host.designer.dragon.dragging;
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed get instances() {
|
|
||||||
return this.host.getComponentInstances(this.props.node);
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { instances } = this;
|
|
||||||
const { node } = this.props;
|
|
||||||
const designer = this.host.designer;
|
|
||||||
|
|
||||||
if (!instances || instances.length < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Fragment key={node.id}>
|
|
||||||
{instances.map(instance => {
|
|
||||||
const observed = designer.createOffsetObserver({
|
|
||||||
node,
|
|
||||||
instance,
|
|
||||||
});
|
|
||||||
if (!observed) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return <OutlineSelectingInstance key={observed.id} dragging={this.dragging} observed={observed} />;
|
|
||||||
})}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class OutlineSelecting extends Component {
|
|
||||||
static contextType = SimulatorContext;
|
|
||||||
|
|
||||||
get host(): SimulatorHost {
|
|
||||||
return this.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
get dragging(): boolean {
|
|
||||||
return this.host.designer.dragon.dragging;
|
|
||||||
}
|
|
||||||
|
|
||||||
@computed get selecting() {
|
|
||||||
const doc = this.host.document;
|
|
||||||
if (doc.suspensed) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const selection = doc.selection;
|
|
||||||
return this.dragging ? selection.getTopNodes() : selection.getNodes();
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const selecting = this.selecting;
|
|
||||||
if (!selecting || selecting.length < 1) {
|
|
||||||
// DIRTY FIX, recore has a bug!
|
|
||||||
return <Fragment />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
{selecting.map(node => (
|
|
||||||
<OutlineSelectingForNode key={node.id} node={node} />
|
|
||||||
))}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
import { createContext } from 'react';
|
|
||||||
import { SimulatorHost } from './host';
|
|
||||||
|
|
||||||
export const SimulatorContext = createContext<SimulatorHost>({} as any);
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
import { SimulatorHostView } from './host/host-view';
|
|
||||||
|
|
||||||
export * from './host/host';
|
|
||||||
export * from './host/host-view';
|
|
||||||
export default SimulatorHostView;
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
// NOTE: 仅做类型标注,切勿做其它用途
|
|
||||||
import { SimulatorHost } from '../host';
|
|
||||||
|
|
||||||
export const host: SimulatorHost = (window as any).LCSimulatorHost;
|
|
||||||
@ -1,284 +0,0 @@
|
|||||||
import { ReactElement, createElement, ReactType } from 'react';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
const mocksCache = new Map<string, (props: any) => ReactElement>();
|
|
||||||
// endpoint element: input,select,video,audio,canvas,textarea
|
|
||||||
//
|
|
||||||
function getBlockElement(tag: string): (props: any) => ReactElement {
|
|
||||||
if (mocksCache.has(tag)) {
|
|
||||||
return mocksCache.get(tag)!;
|
|
||||||
}
|
|
||||||
const mock = ({ className, children, ...rest }: any = {}) => {
|
|
||||||
const props = {
|
|
||||||
...rest,
|
|
||||||
className: classNames('my-intrinsic-container', className),
|
|
||||||
};
|
|
||||||
return createElement(tag, props, children);
|
|
||||||
};
|
|
||||||
|
|
||||||
mock.prototypeConfig = {
|
|
||||||
uri: `@html:${tag}`,
|
|
||||||
selfControlled: true,
|
|
||||||
...(prototypeMap as any)[tag],
|
|
||||||
};
|
|
||||||
|
|
||||||
mocksCache.set(tag, mock);
|
|
||||||
return mock;
|
|
||||||
}
|
|
||||||
|
|
||||||
const HTMLBlock = [
|
|
||||||
'div',
|
|
||||||
'p',
|
|
||||||
'article',
|
|
||||||
'h1',
|
|
||||||
'h2',
|
|
||||||
'h3',
|
|
||||||
'h4',
|
|
||||||
'h5',
|
|
||||||
'h6',
|
|
||||||
'aside',
|
|
||||||
'blockquote',
|
|
||||||
'footer',
|
|
||||||
'form',
|
|
||||||
'header',
|
|
||||||
'table',
|
|
||||||
'tbody',
|
|
||||||
'section',
|
|
||||||
'ul',
|
|
||||||
'li',
|
|
||||||
'span',
|
|
||||||
];
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const HTMLInlineBlock = ['a', 'b', 'span', 'em'];
|
|
||||||
export function getIntrinsicMock(tag: string): ReactType {
|
|
||||||
if (HTMLBlock.indexOf(tag) > -1) {
|
|
||||||
return getBlockElement(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tag as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const prototypeMap = {
|
|
||||||
div: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: 'p',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ul: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
childWhitelist: 'li',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
p: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: 'button,p',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
li: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
parentWhitelist: 'ui,ol',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
span: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
a: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!a',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
b: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
strong: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
em: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
i: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
form: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!form,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
caption: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
input: {
|
|
||||||
isContainer: false,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button,!h1,!h2,!h3,!h4,!h5',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
textarea: {
|
|
||||||
isContainer: false,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
isContainer: false,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
canvas: {
|
|
||||||
isContainer: false,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
br: {
|
|
||||||
isContainer: false,
|
|
||||||
selfControlled: true,
|
|
||||||
},
|
|
||||||
h1: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!p,!h1,!h2,!h3,!h4,!h5,!h6,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
h2: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!p,!h1,!h2,!h3,!h4,!h5,!h6,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
h3: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!p,!h1,!h2,!h3,!h4,!h5,!h6,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
h4: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!p,!h1,!h2,!h3,!h4,!h5,!h6,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
h5: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!p,!h1,!h2,!h3,!h4,!h5,!h6,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
h6: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!p,!h1,!h2,!h3,!h4,!h5,!h6,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
article: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
aside: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
blockquote: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
address: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
section: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!p,!h1,!h2,!h3,!h4,!h5,!h6,!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
summary: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nav: {
|
|
||||||
isContainer: true,
|
|
||||||
selfControlled: true,
|
|
||||||
nesting: {
|
|
||||||
ancestorBlacklist: '!button',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
299
packages/designer/src/component-meta.ts
Normal file
299
packages/designer/src/component-meta.ts
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
import {
|
||||||
|
ComponentMetadata,
|
||||||
|
NpmInfo,
|
||||||
|
NodeData,
|
||||||
|
NodeSchema,
|
||||||
|
ComponentAction,
|
||||||
|
TitleContent,
|
||||||
|
TransformedComponentMetadata,
|
||||||
|
getRegisteredMetadataTransducers,
|
||||||
|
registerMetadataTransducer,
|
||||||
|
computed,
|
||||||
|
} from '@ali/lowcode-globals';
|
||||||
|
import { Node, NodeParent } from './document';
|
||||||
|
import { Designer } from './designer';
|
||||||
|
import { intl } from './locale';
|
||||||
|
import { IconContainer } from './icons/container';
|
||||||
|
import { IconPage } from './icons/page';
|
||||||
|
import { IconComponent } from './icons/component';
|
||||||
|
import { IconRemove } from './icons/remove';
|
||||||
|
import { IconClone } from './icons/clone';
|
||||||
|
|
||||||
|
function ensureAList(list?: string | string[]): string[] | null {
|
||||||
|
if (!list) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(list)) {
|
||||||
|
list = list.split(/ *[ ,|] */).filter(Boolean);
|
||||||
|
}
|
||||||
|
if (list.length < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
function npmToURI(npm: {
|
||||||
|
package: string;
|
||||||
|
exportName?: string;
|
||||||
|
subName?: string;
|
||||||
|
destructuring?: boolean;
|
||||||
|
main?: string;
|
||||||
|
version: string;
|
||||||
|
}): string {
|
||||||
|
const pkg = [];
|
||||||
|
if (npm.package) {
|
||||||
|
pkg.push(npm.package);
|
||||||
|
}
|
||||||
|
if (npm.main) {
|
||||||
|
if (npm.main[0] === '/') {
|
||||||
|
pkg.push(npm.main.slice(1));
|
||||||
|
} else if (npm.main.slice(0, 2) === './') {
|
||||||
|
pkg.push(npm.main.slice(2));
|
||||||
|
} else {
|
||||||
|
pkg.push(npm.main);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let uri = pkg.join('/');
|
||||||
|
uri += `:${npm.destructuring && npm.exportName ? npm.exportName : 'default'}`;
|
||||||
|
|
||||||
|
if (npm.subName) {
|
||||||
|
uri += `.${npm.subName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ComponentMeta {
|
||||||
|
readonly isComponentMeta = true;
|
||||||
|
private _uri?: string;
|
||||||
|
get uri(): string {
|
||||||
|
return this._uri!;
|
||||||
|
}
|
||||||
|
private _npm?: NpmInfo;
|
||||||
|
get npm() {
|
||||||
|
return this._npm;
|
||||||
|
}
|
||||||
|
private _componentName?: string;
|
||||||
|
get componentName(): string {
|
||||||
|
return this._componentName!;
|
||||||
|
}
|
||||||
|
private _isContainer?: boolean;
|
||||||
|
get isContainer(): boolean {
|
||||||
|
return this._isContainer! || this.isRootComponent();
|
||||||
|
}
|
||||||
|
private _isModal?: boolean;
|
||||||
|
get isModal(): boolean {
|
||||||
|
return this._isModal!;
|
||||||
|
}
|
||||||
|
private _descriptor?: string;
|
||||||
|
get descriptor(): string | undefined {
|
||||||
|
return this._descriptor;
|
||||||
|
}
|
||||||
|
private _rectSelector?: string;
|
||||||
|
get rectSelector(): string | undefined {
|
||||||
|
return this._rectSelector;
|
||||||
|
}
|
||||||
|
private _transformedMetadata?: TransformedComponentMetadata;
|
||||||
|
get configure() {
|
||||||
|
const config = this._transformedMetadata?.configure;
|
||||||
|
return config?.combined || config?.props || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private parentWhitelist?: string[] | null;
|
||||||
|
private childWhitelist?: string[] | null;
|
||||||
|
|
||||||
|
private _title?: TitleContent;
|
||||||
|
get title() {
|
||||||
|
return this._title || this.componentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get icon() {
|
||||||
|
// give Slot default icon
|
||||||
|
return (
|
||||||
|
this._transformedMetadata?.icon ||
|
||||||
|
(this.componentName === 'Page' ? IconPage : this.isContainer ? IconContainer : IconComponent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _acceptable?: boolean;
|
||||||
|
get acceptable(): boolean {
|
||||||
|
return this._acceptable!;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(readonly designer: Designer, metadata: ComponentMetadata) {
|
||||||
|
this.parseMetadata(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseMetadata(metadta: ComponentMetadata) {
|
||||||
|
const { componentName, uri, npm } = metadta;
|
||||||
|
this._npm = npm;
|
||||||
|
this._uri = uri || (npm ? npmToURI(npm) : componentName);
|
||||||
|
this._componentName = componentName;
|
||||||
|
|
||||||
|
metadta.uri = this._uri;
|
||||||
|
// 额外转换逻辑
|
||||||
|
this._transformedMetadata = this.transformMetadata(metadta);
|
||||||
|
|
||||||
|
const title = this._transformedMetadata.title;
|
||||||
|
if (title && typeof title === 'string') {
|
||||||
|
this._title = {
|
||||||
|
type: 'i18n',
|
||||||
|
'en-US': this.componentName,
|
||||||
|
'zh-CN': title,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { configure = {} } = this._transformedMetadata;
|
||||||
|
this._acceptable = false;
|
||||||
|
|
||||||
|
const { component } = configure;
|
||||||
|
if (component) {
|
||||||
|
this._isContainer = component.isContainer ? true : false;
|
||||||
|
this._isModal = component.isModal ? true : false;
|
||||||
|
this._descriptor = component.descriptor;
|
||||||
|
this._rectSelector = component.rectSelector;
|
||||||
|
if (component.nestingRule) {
|
||||||
|
const { parentWhitelist, childWhitelist } = component.nestingRule;
|
||||||
|
this.parentWhitelist = ensureAList(parentWhitelist);
|
||||||
|
this.childWhitelist = ensureAList(childWhitelist);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._isContainer = false;
|
||||||
|
this._isModal = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private transformMetadata(metadta: ComponentMetadata): TransformedComponentMetadata {
|
||||||
|
const result = getRegisteredMetadataTransducers().reduce((prevMetadata, current) => {
|
||||||
|
return current(prevMetadata);
|
||||||
|
}, preprocessMetadata(metadta));
|
||||||
|
|
||||||
|
if (!result.configure) {
|
||||||
|
result.configure = {};
|
||||||
|
}
|
||||||
|
return result as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
isRootComponent() {
|
||||||
|
return this.componentName === 'Page' || this.componentName === 'Block' || this.componentName === 'Component';
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed get availableActions() {
|
||||||
|
let { disableBehaviors, actions } = this._transformedMetadata?.configure.component || {};
|
||||||
|
actions = builtinComponentActions.concat(this.designer.getGlobalComponentActions() || [], actions || []);
|
||||||
|
if (!disableBehaviors && this.isRootComponent()) {
|
||||||
|
disableBehaviors = ['copy', 'remove'];
|
||||||
|
}
|
||||||
|
if (disableBehaviors) {
|
||||||
|
return actions.filter(action => disableBehaviors!.indexOf(action.name) < 0);
|
||||||
|
}
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMetadata(metadata: ComponentMetadata) {
|
||||||
|
this.parseMetadata(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
getMetadata(): TransformedComponentMetadata {
|
||||||
|
return this._transformedMetadata!;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNestingUp(my: Node | NodeData, parent: NodeParent) {
|
||||||
|
if (this.parentWhitelist) {
|
||||||
|
return this.parentWhitelist.includes(parent.componentName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkNestingDown(my: Node, target: Node | NodeSchema) {
|
||||||
|
if (this.childWhitelist) {
|
||||||
|
return this.childWhitelist.includes(target.componentName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMetadata {
|
||||||
|
if (metadata.configure) {
|
||||||
|
if (Array.isArray(metadata.configure)) {
|
||||||
|
return {
|
||||||
|
...metadata,
|
||||||
|
configure: {
|
||||||
|
props: metadata.configure,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return metadata as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...metadata,
|
||||||
|
configure: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
registerMetadataTransducer(metadata => {
|
||||||
|
const { configure, componentName } = metadata;
|
||||||
|
const { component = {} } = configure;
|
||||||
|
if (!component.nestingRule) {
|
||||||
|
let m;
|
||||||
|
// uri match xx.Group set subcontrolling: true, childWhiteList
|
||||||
|
if ((m = /^(.+)\.Group$/.exec(componentName))) {
|
||||||
|
// component.subControlling = true;
|
||||||
|
if (!component.nestingRule) {
|
||||||
|
component.nestingRule = {
|
||||||
|
childWhitelist: [`${m[1]}`],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// uri match xx.Node set selfControlled: false, parentWhiteList
|
||||||
|
else if ((m = /^(.+)\.Node$/.exec(componentName))) {
|
||||||
|
// component.selfControlled = false;
|
||||||
|
component.nestingRule = {
|
||||||
|
parentWhitelist: [`${m[1]}`, componentName],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// uri match .Item .Node .Option set parentWhiteList
|
||||||
|
else if ((m = /^(.+)\.(Item|Node|Option)$/.exec(componentName))) {
|
||||||
|
component.nestingRule = {
|
||||||
|
parentWhitelist: [`${m[1]}`],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (component.isModal == null && /Dialog/.test(componentName)) {
|
||||||
|
component.isModal = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...metadata,
|
||||||
|
configure: {
|
||||||
|
...configure,
|
||||||
|
component,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const builtinComponentActions: ComponentAction[] = [
|
||||||
|
{
|
||||||
|
name: 'remove',
|
||||||
|
content: {
|
||||||
|
icon: IconRemove,
|
||||||
|
description: intl('remove'),
|
||||||
|
action(node: Node) {
|
||||||
|
node.remove();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'copy',
|
||||||
|
content: {
|
||||||
|
icon: IconClone,
|
||||||
|
description: intl('copy'),
|
||||||
|
action(node: Node) {
|
||||||
|
// node.remove();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
important: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -1,13 +1,13 @@
|
|||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { LocationDetail } from './location';
|
import { LocationDetail } from './location';
|
||||||
import Node, { isNode } from '../document/node/node';
|
import { Node, isNode } from '../document/node/node';
|
||||||
|
|
||||||
interface ActiveTarget {
|
export interface ActiveTarget {
|
||||||
node: Node;
|
node: Node;
|
||||||
detail?: LocationDetail;
|
detail?: LocationDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ActiveTracker {
|
export class ActiveTracker {
|
||||||
private emitter = new EventEmitter();
|
private emitter = new EventEmitter();
|
||||||
|
|
||||||
track(target: ActiveTarget | Node) {
|
track(target: ActiveTarget | Node) {
|
||||||
@ -5,6 +5,7 @@ function getDataFromPasteEvent(event: ClipboardEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// { componentsMap, componentsTree, ... }
|
||||||
return JSON.parse(clipboardData.getData('text/plain'));
|
return JSON.parse(clipboardData.getData('text/plain'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
/*
|
/*
|
||||||
@ -17,11 +18,13 @@ function getDataFromPasteEvent(event: ClipboardEvent) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
// paste the text by div
|
// TODO: open the parser implement
|
||||||
|
return null;
|
||||||
|
/*
|
||||||
return {
|
return {
|
||||||
code: clipboardData.getData('text/plain'),
|
code: clipboardData.getData('text/plain'),
|
||||||
maps: {},
|
maps: {},
|
||||||
};
|
};*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +36,7 @@ class Clipboard {
|
|||||||
this.isCopyPaster(e.target);
|
this.isCopyPaster(e.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
isCopyPaster(el: any) {
|
private isCopyPaster(el: any) {
|
||||||
return this.copyPasters.includes(el);
|
return this.copyPasters.includes(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +60,9 @@ class Clipboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
injectCopyPaster(document: Document) {
|
injectCopyPaster(document: Document) {
|
||||||
|
if (this.copyPasters.find(x => x.ownerDocument === document)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const copyPaster = document.createElement<'textarea'>('textarea');
|
const copyPaster = document.createElement<'textarea'>('textarea');
|
||||||
copyPaster.style.cssText = 'position: relative;left: -9999px;';
|
copyPaster.style.cssText = 'position: relative;left: -9999px;';
|
||||||
document.body.appendChild(copyPaster);
|
document.body.appendChild(copyPaster);
|
||||||
@ -1,224 +0,0 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
import Node, { NodeParent } from './document/node/node';
|
|
||||||
import { NodeData, NodeSchema } from './schema';
|
|
||||||
import { PropConfig } from './prop-config';
|
|
||||||
|
|
||||||
export interface NestingRule {
|
|
||||||
childWhitelist?: string[];
|
|
||||||
parentWhitelist?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Configure {
|
|
||||||
props?: any[];
|
|
||||||
styles?: object;
|
|
||||||
events?: object;
|
|
||||||
component?: {
|
|
||||||
isContainer?: boolean;
|
|
||||||
isModal?: boolean;
|
|
||||||
descriptor?: string;
|
|
||||||
nestingRule?: NestingRule;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ComponentMetadata {
|
|
||||||
componentName: string;
|
|
||||||
/**
|
|
||||||
* unique id
|
|
||||||
*/
|
|
||||||
uri?: string;
|
|
||||||
/**
|
|
||||||
* title or description
|
|
||||||
*/
|
|
||||||
title?: string;
|
|
||||||
/**
|
|
||||||
* svg icon for component
|
|
||||||
*/
|
|
||||||
icon?: string | ReactNode;
|
|
||||||
tags?: string[];
|
|
||||||
description?: string;
|
|
||||||
docUrl?: string;
|
|
||||||
screenshot?: string;
|
|
||||||
devMode?: 'procode' | 'lowcode';
|
|
||||||
npm?: {
|
|
||||||
package: string;
|
|
||||||
exportName: string;
|
|
||||||
subName: string;
|
|
||||||
main: string;
|
|
||||||
destructuring: boolean;
|
|
||||||
version: string;
|
|
||||||
};
|
|
||||||
props?: PropConfig[];
|
|
||||||
configure?: any[] | Configure;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TransformedComponentMetadata extends ComponentMetadata {
|
|
||||||
configure?: Configure & {
|
|
||||||
combined?: any[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureAList(list?: string | string[]): string[] | null {
|
|
||||||
if (!list) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (!Array.isArray(list)) {
|
|
||||||
list = list.split(/ *[ ,|] */).filter(Boolean);
|
|
||||||
}
|
|
||||||
if (list.length < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
function npmToURI(npm: {
|
|
||||||
package: string;
|
|
||||||
exportName?: string;
|
|
||||||
subName?: string;
|
|
||||||
destructuring?: boolean;
|
|
||||||
main?: string;
|
|
||||||
version: string;
|
|
||||||
}): string {
|
|
||||||
const pkg = [];
|
|
||||||
if (npm.package) {
|
|
||||||
pkg.push(npm.package);
|
|
||||||
}
|
|
||||||
if (npm.main) {
|
|
||||||
if (npm.main[0] === '/') {
|
|
||||||
pkg.push(npm.main.slice(1));
|
|
||||||
} else if (npm.main.slice(0, 2) === './') {
|
|
||||||
pkg.push(npm.main.slice(2));
|
|
||||||
} else {
|
|
||||||
pkg.push(npm.main);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let uri = pkg.join('/');
|
|
||||||
uri += `:${npm.destructuring && npm.exportName ? npm.exportName : 'default'}`;
|
|
||||||
|
|
||||||
if (npm.subName) {
|
|
||||||
uri += `.${npm.subName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MetadataTransducer = (prev: ComponentMetadata) => TransformedComponentMetadata;
|
|
||||||
const metadataTransducers: MetadataTransducer[] = [];
|
|
||||||
|
|
||||||
export function registerMetadataTransducer(transducer: MetadataTransducer) {
|
|
||||||
metadataTransducers.push(transducer);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ComponentMeta {
|
|
||||||
readonly isComponentMeta = true;
|
|
||||||
private _uri?: string;
|
|
||||||
get uri(): string {
|
|
||||||
return this._uri!;
|
|
||||||
}
|
|
||||||
private _componentName?: string;
|
|
||||||
get componentName(): string {
|
|
||||||
return this._componentName!;
|
|
||||||
}
|
|
||||||
private _isContainer?: boolean;
|
|
||||||
get isContainer(): boolean {
|
|
||||||
return this._isContainer! || this.isRootComponent();
|
|
||||||
}
|
|
||||||
private _isModal?: boolean;
|
|
||||||
get isModal(): boolean {
|
|
||||||
return this._isModal!;
|
|
||||||
}
|
|
||||||
private _descriptor?: string;
|
|
||||||
get descriptor(): string {
|
|
||||||
return this._descriptor!;
|
|
||||||
}
|
|
||||||
private _acceptable?: boolean;
|
|
||||||
get acceptable(): boolean {
|
|
||||||
return this._acceptable!;
|
|
||||||
}
|
|
||||||
private _transformedMetadata?: TransformedComponentMetadata;
|
|
||||||
get configure() {
|
|
||||||
const config = this._transformedMetadata?.configure;
|
|
||||||
return config?.combined || config?.props || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
private parentWhitelist?: string[] | null;
|
|
||||||
private childWhitelist?: string[] | null;
|
|
||||||
|
|
||||||
get title() {
|
|
||||||
return this._metadata.title || this.componentName;
|
|
||||||
}
|
|
||||||
|
|
||||||
get icon() {
|
|
||||||
return this._metadata.icon;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(private _metadata: ComponentMetadata) {
|
|
||||||
this.parseMetadata(_metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseMetadata(metadta: ComponentMetadata) {
|
|
||||||
const { componentName, uri, npm, props } = metadta;
|
|
||||||
this._uri = uri || (npm ? npmToURI(npm) : componentName);
|
|
||||||
this._componentName = componentName;
|
|
||||||
|
|
||||||
metadta.uri = this._uri;
|
|
||||||
// 额外转换逻辑
|
|
||||||
this._transformedMetadata = this.transformMetadata(metadta);
|
|
||||||
|
|
||||||
const { configure = {} } = this._transformedMetadata;
|
|
||||||
this._acceptable = false;
|
|
||||||
|
|
||||||
const { component } = configure;
|
|
||||||
if (component) {
|
|
||||||
this._isContainer = component.isContainer ? true : false;
|
|
||||||
this._isModal = component.isModal ? true : false;
|
|
||||||
this._descriptor = component.descriptor;
|
|
||||||
if (component.nestingRule) {
|
|
||||||
const { parentWhitelist, childWhitelist } = component.nestingRule;
|
|
||||||
this.parentWhitelist = ensureAList(parentWhitelist);
|
|
||||||
this.childWhitelist = ensureAList(childWhitelist);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this._isContainer = false;
|
|
||||||
this._isModal = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private transformMetadata(metadta: ComponentMetadata): TransformedComponentMetadata {
|
|
||||||
const result = metadataTransducers.reduce((prevMetadata, current) => {
|
|
||||||
return current(prevMetadata);
|
|
||||||
}, metadta);
|
|
||||||
|
|
||||||
if (!result.configure) {
|
|
||||||
result.configure = {};
|
|
||||||
}
|
|
||||||
return result as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
isRootComponent() {
|
|
||||||
return this.componentName === 'Page' || this.componentName === 'Block' || this.componentName === 'Component';
|
|
||||||
}
|
|
||||||
|
|
||||||
set metadata(metadata: ComponentMetadata) {
|
|
||||||
this._metadata = metadata;
|
|
||||||
this.parseMetadata(metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
get metadata(): ComponentMetadata {
|
|
||||||
return this._metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNestingUp(my: Node | NodeData, parent: NodeParent) {
|
|
||||||
if (this.parentWhitelist) {
|
|
||||||
return this.parentWhitelist.includes(parent.componentName);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNestingDown(my: Node, target: Node | NodeSchema) {
|
|
||||||
if (this.childWhitelist) {
|
|
||||||
return this.childWhitelist.includes(target.componentName);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,13 @@
|
|||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Designer, { DesignerProps } from './designer';
|
import { TipContainer } from '@ali/lowcode-globals';
|
||||||
import BuiltinDragGhostComponent from '../builtins/drag-ghost';
|
import BuiltinDragGhostComponent from './drag-ghost';
|
||||||
import ProjectView from './project-view';
|
import { Designer, DesignerProps } from './designer';
|
||||||
|
import { ProjectView } from '../project';
|
||||||
import './designer.less';
|
import './designer.less';
|
||||||
|
import clipboard from './clipboard';
|
||||||
|
|
||||||
export default class DesignerView extends Component<DesignerProps> {
|
export class DesignerView extends Component<DesignerProps> {
|
||||||
readonly designer: Designer;
|
readonly designer: Designer;
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
@ -18,7 +20,7 @@ export default class DesignerView extends Component<DesignerProps> {
|
|||||||
const props = this.props;
|
const props = this.props;
|
||||||
if (
|
if (
|
||||||
nextProps.className !== props.className ||
|
nextProps.className !== props.className ||
|
||||||
nextProps.style != props.style ||
|
nextProps.style !== props.style ||
|
||||||
nextProps.dragGhostComponent !== props.dragGhostComponent
|
nextProps.dragGhostComponent !== props.dragGhostComponent
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
@ -31,6 +33,8 @@ export default class DesignerView extends Component<DesignerProps> {
|
|||||||
if (onMount) {
|
if (onMount) {
|
||||||
onMount(this.designer);
|
onMount(this.designer);
|
||||||
}
|
}
|
||||||
|
clipboard.injectCopyPaster(document)
|
||||||
|
this.designer.postEvent('mount', this.designer);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
@ -45,6 +49,7 @@ export default class DesignerView extends Component<DesignerProps> {
|
|||||||
<div className={classNames('lc-designer', className)} style={style}>
|
<div className={classNames('lc-designer', className)} style={style}>
|
||||||
<DragGhost designer={this.designer} />
|
<DragGhost designer={this.designer} />
|
||||||
<ProjectView designer={this.designer} />
|
<ProjectView designer={this.designer} />
|
||||||
|
<TipContainer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,26 +48,6 @@
|
|||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
.lc-project {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
.lc-document {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
&-hidden {
|
|
||||||
// todo:
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lc-simulator-shell {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,20 +1,25 @@
|
|||||||
import { ComponentType as ReactComponentType } from 'react';
|
import { ComponentType } from 'react';
|
||||||
import { obx, computed, autorun } from '@recore/obx';
|
|
||||||
import BuiltinSimulatorView from '../builtins/simulator';
|
|
||||||
import Project from './project';
|
|
||||||
import { ProjectSchema, NpmInfo } from './schema';
|
|
||||||
import Dragon, { isDragNodeObject, isDragNodeDataObject, LocateEvent, DragObject } from './helper/dragon';
|
|
||||||
import ActiveTracker from './helper/active-tracker';
|
|
||||||
import Hovering from './helper/hovering';
|
|
||||||
import Location, { LocationData, isLocationChildrenDetail } from './helper/location';
|
|
||||||
import DocumentModel from './document/document-model';
|
|
||||||
import Node, { insertChildren } from './document/node/node';
|
|
||||||
import { isRootNode } from './document/node/root-node';
|
|
||||||
import { ComponentMetadata, ComponentMeta } from './component-meta';
|
|
||||||
import Scroller, { IScrollable } from './helper/scroller';
|
|
||||||
import { INodeSelector } from './simulator';
|
|
||||||
import OffsetObserver, { createOffsetObserver } from './helper/offset-observer';
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
import {
|
||||||
|
ProjectSchema,
|
||||||
|
ComponentMetadata,
|
||||||
|
ComponentAction,
|
||||||
|
NpmInfo,
|
||||||
|
obx,
|
||||||
|
computed,
|
||||||
|
autorun,
|
||||||
|
} from '@ali/lowcode-globals';
|
||||||
|
import { Project } from '../project';
|
||||||
|
import { Node, DocumentModel, insertChildren, isRootNode, NodeParent } from '../document';
|
||||||
|
import { ComponentMeta } from '../component-meta';
|
||||||
|
import { INodeSelector } from '../simulator';
|
||||||
|
import { Scroller, IScrollable } from './scroller';
|
||||||
|
import { Dragon, isDragNodeObject, isDragNodeDataObject, LocateEvent, DragObject } from './dragon';
|
||||||
|
import { ActiveTracker } from './active-tracker';
|
||||||
|
import { Hovering } from './hovering';
|
||||||
|
import { DropLocation, LocationData, isLocationChildrenDetail } from './location';
|
||||||
|
import { OffsetObserver, createOffsetObserver } from './offset-observer';
|
||||||
|
import { focusing } from './focusing';
|
||||||
|
|
||||||
export interface DesignerProps {
|
export interface DesignerProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -22,20 +27,20 @@ export interface DesignerProps {
|
|||||||
defaultSchema?: ProjectSchema;
|
defaultSchema?: ProjectSchema;
|
||||||
hotkeys?: object;
|
hotkeys?: object;
|
||||||
simulatorProps?: object | ((document: DocumentModel) => object);
|
simulatorProps?: object | ((document: DocumentModel) => object);
|
||||||
simulatorComponent?: ReactComponentType<any>;
|
simulatorComponent?: ComponentType<any>;
|
||||||
dragGhostComponent?: ReactComponentType<any>;
|
dragGhostComponent?: ComponentType<any>;
|
||||||
suspensed?: boolean;
|
suspensed?: boolean;
|
||||||
componentsDescription?: ComponentMetadata[];
|
componentMetadatas?: ComponentMetadata[];
|
||||||
eventPipe?: EventEmitter;
|
eventPipe?: EventEmitter;
|
||||||
|
globalComponentActions?: ComponentAction[];
|
||||||
onMount?: (designer: Designer) => void;
|
onMount?: (designer: Designer) => void;
|
||||||
onDragstart?: (e: LocateEvent) => void;
|
onDragstart?: (e: LocateEvent) => void;
|
||||||
onDrag?: (e: LocateEvent) => void;
|
onDrag?: (e: LocateEvent) => void;
|
||||||
onDragend?: (e: { dragObject: DragObject; copy: boolean }, loc?: Location) => void;
|
onDragend?: (e: { dragObject: DragObject; copy: boolean }, loc?: DropLocation) => void;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Designer {
|
export class Designer {
|
||||||
// readonly hotkey: Hotkey;
|
|
||||||
readonly dragon = new Dragon(this);
|
readonly dragon = new Dragon(this);
|
||||||
readonly activeTracker = new ActiveTracker();
|
readonly activeTracker = new ActiveTracker();
|
||||||
readonly hovering = new Hovering();
|
readonly hovering = new Hovering();
|
||||||
@ -58,7 +63,7 @@ export default class Designer {
|
|||||||
|
|
||||||
this.project = new Project(this, props.defaultSchema);
|
this.project = new Project(this, props.defaultSchema);
|
||||||
|
|
||||||
this.dragon.onDragstart(e => {
|
this.dragon.onDragstart((e) => {
|
||||||
this.hovering.enable = false;
|
this.hovering.enable = false;
|
||||||
const { dragObject } = e;
|
const { dragObject } = e;
|
||||||
if (isDragNodeObject(dragObject)) {
|
if (isDragNodeObject(dragObject)) {
|
||||||
@ -75,14 +80,14 @@ export default class Designer {
|
|||||||
this.postEvent('dragstart', e);
|
this.postEvent('dragstart', e);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dragon.onDrag(e => {
|
this.dragon.onDrag((e) => {
|
||||||
if (this.props?.onDrag) {
|
if (this.props?.onDrag) {
|
||||||
this.props.onDrag(e);
|
this.props.onDrag(e);
|
||||||
}
|
}
|
||||||
this.postEvent('drag', e);
|
this.postEvent('drag', e);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dragon.onDragend(e => {
|
this.dragon.onDragend((e) => {
|
||||||
const { dragObject, copy } = e;
|
const { dragObject, copy } = e;
|
||||||
const loc = this._dropLocation;
|
const loc = this._dropLocation;
|
||||||
if (loc) {
|
if (loc) {
|
||||||
@ -96,7 +101,7 @@ export default class Designer {
|
|||||||
nodes = insertChildren(loc.target, nodeData, loc.detail.index);
|
nodes = insertChildren(loc.target, nodeData, loc.detail.index);
|
||||||
}
|
}
|
||||||
if (nodes) {
|
if (nodes) {
|
||||||
loc.document.selection.selectAll(nodes.map(o => o.id));
|
loc.document.selection.selectAll(nodes.map((o) => o.id));
|
||||||
setTimeout(() => this.activeTracker.track(nodes![0]), 10);
|
setTimeout(() => this.activeTracker.track(nodes![0]), 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,22 +153,27 @@ export default class Designer {
|
|||||||
setupSelection();
|
setupSelection();
|
||||||
setupHistory();
|
setupHistory();
|
||||||
});
|
});
|
||||||
|
this.postEvent('designer.init', this);
|
||||||
setupSelection();
|
setupSelection();
|
||||||
setupHistory();
|
setupHistory();
|
||||||
|
|
||||||
this.postEvent('designer.ready', this);
|
// TODO: 先简单实现,后期通过焦点赋值
|
||||||
|
focusing.focusDesigner = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
postEvent(event: string, ...args: any[]) {
|
postEvent(event: string, ...args: any[]) {
|
||||||
this.props?.eventPipe?.emit(`designer.${event}`, ...args);
|
this.props?.eventPipe?.emit(`designer.${event}`, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dropLocation?: Location;
|
private _dropLocation?: DropLocation;
|
||||||
/**
|
/**
|
||||||
* 创建插入位置,考虑放到 dragon 中
|
* 创建插入位置,考虑放到 dragon 中
|
||||||
*/
|
*/
|
||||||
createLocation(locationData: LocationData): Location {
|
createLocation(locationData: LocationData): DropLocation {
|
||||||
const loc = new Location(locationData);
|
const loc = new DropLocation(locationData);
|
||||||
|
if (this._dropLocation && this._dropLocation.document !== loc.document) {
|
||||||
|
this._dropLocation.document.internalSetDropLocation(null);
|
||||||
|
}
|
||||||
this._dropLocation = loc;
|
this._dropLocation = loc;
|
||||||
loc.document.internalSetDropLocation(loc);
|
loc.document.internalSetDropLocation(loc);
|
||||||
this.activeTracker.track({ node: loc.target, detail: loc.detail });
|
this.activeTracker.track({ node: loc.target, detail: loc.detail });
|
||||||
@ -191,7 +201,7 @@ export default class Designer {
|
|||||||
/**
|
/**
|
||||||
* 获得合适的插入位置
|
* 获得合适的插入位置
|
||||||
*/
|
*/
|
||||||
getSuitableInsertion() {
|
getSuitableInsertion(): { target: NodeParent; index?: number } | null {
|
||||||
const activedDoc = this.project.currentDocument;
|
const activedDoc = this.project.currentDocument;
|
||||||
if (!activedDoc) {
|
if (!activedDoc) {
|
||||||
return null;
|
return null;
|
||||||
@ -215,7 +225,8 @@ export default class Designer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private props?: DesignerProps;
|
private props?: DesignerProps;
|
||||||
setProps(props: DesignerProps) {
|
setProps(nextProps: DesignerProps) {
|
||||||
|
const props = this.props ? { ...this.props, ...nextProps } : nextProps;
|
||||||
if (this.props) {
|
if (this.props) {
|
||||||
// check hotkeys
|
// check hotkeys
|
||||||
// TODO:
|
// TODO:
|
||||||
@ -229,8 +240,8 @@ export default class Designer {
|
|||||||
if (props.suspensed !== this.props.suspensed && props.suspensed != null) {
|
if (props.suspensed !== this.props.suspensed && props.suspensed != null) {
|
||||||
this.suspensed = props.suspensed;
|
this.suspensed = props.suspensed;
|
||||||
}
|
}
|
||||||
if (props.componentsDescription !== this.props.componentsDescription && props.componentsDescription != null) {
|
if (props.componentMetadatas !== this.props.componentMetadatas && props.componentMetadatas != null) {
|
||||||
this.buildComponentMetasMap(props.componentsDescription);
|
this.buildComponentMetasMap(props.componentMetadatas);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// init hotkeys
|
// init hotkeys
|
||||||
@ -246,8 +257,8 @@ export default class Designer {
|
|||||||
if (props.suspensed != null) {
|
if (props.suspensed != null) {
|
||||||
this.suspensed = props.suspensed;
|
this.suspensed = props.suspensed;
|
||||||
}
|
}
|
||||||
if (props.componentsDescription != null) {
|
if (props.componentMetadatas != null) {
|
||||||
this.buildComponentMetasMap(props.componentsDescription);
|
this.buildComponentMetasMap(props.componentMetadatas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.props = props;
|
this.props = props;
|
||||||
@ -257,10 +268,10 @@ export default class Designer {
|
|||||||
return this.props ? this.props[key] : null;
|
return this.props ? this.props[key] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@obx.ref private _simulatorComponent?: ReactComponentType<any>;
|
@obx.ref private _simulatorComponent?: ComponentType<any>;
|
||||||
|
|
||||||
@computed get simulatorComponent(): ReactComponentType<any> {
|
@computed get simulatorComponent(): ComponentType<any> | undefined {
|
||||||
return this._simulatorComponent || BuiltinSimulatorView;
|
return this._simulatorComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@obx.ref private _simulatorProps?: object | ((document: DocumentModel) => object);
|
@obx.ref private _simulatorProps?: object | ((document: DocumentModel) => object);
|
||||||
@ -284,30 +295,30 @@ export default class Designer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get schema(): ProjectSchema {
|
get schema(): ProjectSchema {
|
||||||
return this.project.schema;
|
return this.project.getSchema();
|
||||||
}
|
}
|
||||||
|
|
||||||
set schema(schema: ProjectSchema) {
|
setSchema(schema?: ProjectSchema) {
|
||||||
// todo:
|
this.project.load(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
@obx.val private _componentMetasMap = new Map<string, ComponentMeta>();
|
@obx.val private _componentMetasMap = new Map<string, ComponentMeta>();
|
||||||
private _lostComponentMetasMap = new Map<string, ComponentMeta>();
|
private _lostComponentMetasMap = new Map<string, ComponentMeta>();
|
||||||
|
|
||||||
private buildComponentMetasMap(metas: ComponentMetadata[]) {
|
private buildComponentMetasMap(metas: ComponentMetadata[]) {
|
||||||
metas.forEach(data => {
|
metas.forEach((data) => {
|
||||||
const key = data.componentName;
|
const key = data.componentName;
|
||||||
let meta = this._componentMetasMap.get(key);
|
let meta = this._componentMetasMap.get(key);
|
||||||
if (meta) {
|
if (meta) {
|
||||||
meta.metadata = data;
|
meta.setMetadata(data);
|
||||||
} else {
|
} else {
|
||||||
meta = this._lostComponentMetasMap.get(key);
|
meta = this._lostComponentMetasMap.get(key);
|
||||||
|
|
||||||
if (meta) {
|
if (meta) {
|
||||||
meta.metadata = data;
|
meta.setMetadata(data);
|
||||||
this._lostComponentMetasMap.delete(key);
|
this._lostComponentMetasMap.delete(key);
|
||||||
} else {
|
} else {
|
||||||
meta = new ComponentMeta(data);
|
meta = new ComponentMeta(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._componentMetasMap.set(key, meta);
|
this._componentMetasMap.set(key, meta);
|
||||||
@ -315,6 +326,10 @@ export default class Designer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getGlobalComponentActions(): ComponentAction[] | null {
|
||||||
|
return this.props?.globalComponentActions || null;
|
||||||
|
}
|
||||||
|
|
||||||
getComponentMeta(componentName: string, generateMetadata?: () => ComponentMetadata | null): ComponentMeta {
|
getComponentMeta(componentName: string, generateMetadata?: () => ComponentMetadata | null): ComponentMeta {
|
||||||
if (this._componentMetasMap.has(componentName)) {
|
if (this._componentMetasMap.has(componentName)) {
|
||||||
return this._componentMetasMap.get(componentName)!;
|
return this._componentMetasMap.get(componentName)!;
|
||||||
@ -324,7 +339,7 @@ export default class Designer {
|
|||||||
return this._lostComponentMetasMap.get(componentName)!;
|
return this._lostComponentMetasMap.get(componentName)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = new ComponentMeta({
|
const meta = new ComponentMeta(this, {
|
||||||
componentName,
|
componentName,
|
||||||
...(generateMetadata ? generateMetadata() : null),
|
...(generateMetadata ? generateMetadata() : null),
|
||||||
});
|
});
|
||||||
@ -337,7 +352,9 @@ export default class Designer {
|
|||||||
@computed get componentsMap(): { [key: string]: NpmInfo } {
|
@computed get componentsMap(): { [key: string]: NpmInfo } {
|
||||||
const maps: any = {};
|
const maps: any = {};
|
||||||
this._componentMetasMap.forEach((config, key) => {
|
this._componentMetasMap.forEach((config, key) => {
|
||||||
maps[key] = config.metadata.npm;
|
if (config.npm) {
|
||||||
|
maps[key] = config.npm;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return maps;
|
return maps;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user