mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-04-19 20:08:05 +00:00
Merge into feat/code-generator
This commit is contained in:
commit
397ad5b93d
3
.gitignore
vendored
3
.gitignore
vendored
@ -100,3 +100,6 @@ typings/
|
||||
|
||||
# mac config files
|
||||
.DS_Store
|
||||
|
||||
# codealike
|
||||
codealike.json
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#### 创建新包:
|
||||
|
||||
- `./create.sh <package-name>`
|
||||
- `./scripts/create.sh <package-name>`
|
||||
|
||||
#### 跑起来:
|
||||
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
<!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>
|
||||
@ -1,23 +0,0 @@
|
||||
<!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>
|
||||
79
deploy-space/static/index.html
Normal file
79
deploy-space/static/index.html
Normal file
@ -0,0 +1,79 @@
|
||||
<!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/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js"></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="./editor-preset-vision.css" />
|
||||
<!-- lowcode engine app -->
|
||||
<link rel="stylesheet" href="./lowcode-editor.css" />
|
||||
<script>
|
||||
window.pageConfig = {
|
||||
env: 'release',
|
||||
locale: 'zh_CN',
|
||||
pageType: 'single',
|
||||
deviceType: 'web',
|
||||
appName: '基础包管理后台',
|
||||
appType: '',
|
||||
templateType: '',
|
||||
pageId: 'FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V',
|
||||
slug: 'test',
|
||||
appMode: 'back',
|
||||
isAppAdmin: 'y',
|
||||
isSuperAdmin: 'n',
|
||||
isBetaDeveloper: 'n',
|
||||
formType: 'display',
|
||||
title: { en_US: '测试', type: 'i18n', zh_CN: '测试' },
|
||||
urlPrefix: 'https://go.alibaba-inc.com',
|
||||
APIUrlPrefix: 'https://mocks.alibaba-inc.com/mock/lowCodeEngine',
|
||||
devVersion: '0.1.0', // 这个是子应用的变更 id
|
||||
subAppType: '0.1.0',
|
||||
appKey: '',
|
||||
RE_VERSION: '7.1.1',
|
||||
appSource: '',
|
||||
isDomainDefault: 'n',
|
||||
useReleaseBundle: 'n',
|
||||
isDomainPkg: 'n',
|
||||
medusaAppName: '',
|
||||
domainCode: 'kS6SyH',
|
||||
aecp: {
|
||||
mdcDomain: '',
|
||||
projectId: '',
|
||||
appCode: '',
|
||||
},
|
||||
designerConfigs: {},
|
||||
navConfig:
|
||||
'{"appName":{"en_US":"基础包管理后台","key":"","type":"i18n","zh_CN":"基础包管理后台"},"bgColor":"white","data":[{"children":[],"hidden":false,"icon":"","inner":true,"navUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","relateUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","slug":"test","targetNew":false,"title":{"en_US":"测试","type":"i18n","zh_CN":"测试"}}],"isFixed":"y","isFold":"y","isFoldHorizontal":"n","languageChangeUrl":{"en_US":"/common/account/changeAccountLanguage.json","type":"i18n","zh_CN":"/common/account/changeAccountLanguage.json"},"layout":"auto","navStyle":"orange","navTheme":"light","openSubMode":false,"showAppTitle":true,"showCrumb":true,"showIcon":false,"showLanguageChange":true,"showNav":true,"showSearch":"n","singletons":{"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V":{"isFixed":"n","isFold":"n","isFoldHorizontal":"n","showAppTitle":false,"showCrumb":false,"showLanguageChange":false,"showNav":false,"showSearch":"n","singleton":false},"test":{"$ref":"$.singletons.FORM\\-3KYJN7RV\\-DIOD8LLK1WGQ89S7NHA92\\-QJVH497K\\-V"}},"type":"top_fold"}',
|
||||
historyType: 'HASH',
|
||||
isSinglePage: 'n',
|
||||
rhino: 'n',
|
||||
isMiniApp: '',
|
||||
taskId: '',
|
||||
appSchema: 'V5',
|
||||
openSubMode: 'n',
|
||||
};
|
||||
window.g_config = {};
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="lce-container"></div>
|
||||
<!-- lowcode engine globals -->
|
||||
<script src="./editor-preset-vision.js"></script>
|
||||
<script src="https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="//g.alicdn.com/??platform/common/s/1.1/global/global.css,uxcore/uxcore-kuma/2.2.1/orange.min.css">
|
||||
<!-- lowcode engine app -->
|
||||
<script src="./lowcode-editor.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
83
deploy-space/static/preview.html
Normal file
83
deploy-space/static/preview.html
Normal file
@ -0,0 +1,83 @@
|
||||
<!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/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js"></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="./core.css" />
|
||||
<!-- lowcode engine globals -->
|
||||
<link rel="stylesheet" href="./vision-preset.css" />
|
||||
<!-- lowcode engine app -->
|
||||
<link rel="stylesheet" href="./lowcode-editor.css" />
|
||||
<script>
|
||||
window.pageConfig = {
|
||||
env: 'release',
|
||||
locale: 'zh_CN',
|
||||
pageType: 'single',
|
||||
deviceType: 'web',
|
||||
appName: '基础包管理后台',
|
||||
appType: '',
|
||||
templateType: '',
|
||||
pageId: 'FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V',
|
||||
slug: 'test',
|
||||
appMode: 'back',
|
||||
isAppAdmin: 'y',
|
||||
isSuperAdmin: 'n',
|
||||
isBetaDeveloper: 'n',
|
||||
formType: 'display',
|
||||
title: { en_US: '测试', type: 'i18n', zh_CN: '测试' },
|
||||
urlPrefix: 'https://go.alibaba-inc.com',
|
||||
APIUrlPrefix: 'https://mocks.alibaba-inc.com/mock/lowCodeEngine',
|
||||
devVersion: '0.1.0', // 这个是子应用的变更 id
|
||||
subAppType: '0.1.0',
|
||||
appKey: '',
|
||||
RE_VERSION: '7.1.1',
|
||||
appSource: '',
|
||||
isDomainDefault: 'n',
|
||||
useReleaseBundle: 'n',
|
||||
isDomainPkg: 'n',
|
||||
medusaAppName: '',
|
||||
domainCode: 'kS6SyH',
|
||||
aecp: {
|
||||
mdcDomain: '',
|
||||
projectId: '',
|
||||
appCode: '',
|
||||
},
|
||||
designerConfigs: {},
|
||||
navConfig:
|
||||
'{"appName":{"en_US":"基础包管理后台","key":"","type":"i18n","zh_CN":"基础包管理后台"},"bgColor":"white","data":[{"children":[],"hidden":false,"icon":"","inner":true,"navUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","relateUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","slug":"test","targetNew":false,"title":{"en_US":"测试","type":"i18n","zh_CN":"测试"}}],"isFixed":"y","isFold":"y","isFoldHorizontal":"n","languageChangeUrl":{"en_US":"/common/account/changeAccountLanguage.json","type":"i18n","zh_CN":"/common/account/changeAccountLanguage.json"},"layout":"auto","navStyle":"orange","navTheme":"light","openSubMode":false,"showAppTitle":true,"showCrumb":true,"showIcon":false,"showLanguageChange":true,"showNav":true,"showSearch":"n","singletons":{"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V":{"isFixed":"n","isFold":"n","isFoldHorizontal":"n","showAppTitle":false,"showCrumb":false,"showLanguageChange":false,"showNav":false,"showSearch":"n","singleton":false},"test":{"$ref":"$.singletons.FORM\\-3KYJN7RV\\-DIOD8LLK1WGQ89S7NHA92\\-QJVH497K\\-V"}},"type":"top_fold"}',
|
||||
historyType: 'HASH',
|
||||
isSinglePage: 'n',
|
||||
rhino: 'n',
|
||||
isMiniApp: '',
|
||||
taskId: '',
|
||||
appSchema: 'V5',
|
||||
openSubMode: 'n',
|
||||
};
|
||||
window.g_config = {};
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="lce-container"></div>
|
||||
<!-- lowcode engine globals -->
|
||||
<script src="./core.js"></script>
|
||||
<!-- lowcode engine globals -->
|
||||
<script src="./vision-preset.js"></script>
|
||||
<script src="https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="//g.alicdn.com/??platform/common/s/1.1/global/global.css,uxcore/uxcore-kuma/2.2.1/orange.min.css">
|
||||
<!-- lowcode engine app -->
|
||||
<script src="./lowcode-editor.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -10,10 +10,10 @@
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"build": "lerna run build --stream",
|
||||
"build": "./scripts/build.sh",
|
||||
"clean": "rm -rf ./packages/*/lib ./packages/*/es ./packages/*/dist ./packages/*/build",
|
||||
"commit": "git-cz",
|
||||
"pub": "lerna publish",
|
||||
"pub": "lerna publish --cd-version patch",
|
||||
"setup": "./scripts/setup.sh",
|
||||
"start": "./scripts/start.sh",
|
||||
"test": "lerna run test --stream",
|
||||
@ -48,5 +48,9 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"tnpm": {
|
||||
"mode": "yarn",
|
||||
"lockfile": "enable"
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,38 @@
|
||||
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.6"></a>
|
||||
## [0.8.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-code-generator@0.8.5...@ali/lowcode-code-generator@0.8.6) (2020-06-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 更改生成 id 的规则, 否则命中 recore 解析 id 的一个限制 ([5adff44](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5adff44))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.8.5"></a>
|
||||
## [0.8.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-code-generator@0.8.4...@ali/lowcode-code-generator@0.8.5) (2020-04-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* enhance compile config ([2899149](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2899149))
|
||||
* path resolve problem ([b12c0f8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b12c0f8))
|
||||
* post process file error ([389eaf7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/389eaf7))
|
||||
* rm demo in lib ([55630d6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/55630d6))
|
||||
* use webpack for package ([b350a88](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b350a88))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add prettier post processor ([49ac9a3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/49ac9a3))
|
||||
* export publisher ([4a53faa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4a53faa))
|
||||
|
||||
|
||||
|
||||
|
||||
<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)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ali/lowcode-code-generator",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.6",
|
||||
"description": "出码引擎 for LowCode Engine",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
|
||||
@ -3,6 +3,219 @@
|
||||
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.33"></a>
|
||||
## [0.8.33](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.32...@ali/lowcode-demo@0.8.33) (2020-06-24)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.32"></a>
|
||||
## [0.8.32](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.31...@ali/lowcode-demo@0.8.32) (2020-06-23)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.31"></a>
|
||||
## [0.8.31](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.30...@ali/lowcode-demo@0.8.31) (2020-06-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 更改生成 id 的规则, 否则命中 recore 解析 id 的一个限制 ([5adff44](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5adff44))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.8.30"></a>
|
||||
## [0.8.30](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.29...@ali/lowcode-demo@0.8.30) (2020-06-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.29"></a>
|
||||
## [0.8.29](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.28...@ali/lowcode-demo@0.8.29) (2020-06-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* style ([4694331](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4694331))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.8.28"></a>
|
||||
## [0.8.28](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.27...@ali/lowcode-demo@0.8.28) (2020-05-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.27"></a>
|
||||
## [0.8.27](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.26...@ali/lowcode-demo@0.8.27) (2020-05-19)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.26"></a>
|
||||
## [0.8.26](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.25...@ali/lowcode-demo@0.8.26) (2020-05-18)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.25"></a>
|
||||
## [0.8.25](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.24...@ali/lowcode-demo@0.8.25) (2020-05-18)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.24"></a>
|
||||
## [0.8.24](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.23...@ali/lowcode-demo@0.8.24) (2020-05-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.23"></a>
|
||||
## [0.8.23](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.22...@ali/lowcode-demo@0.8.23) (2020-05-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.22"></a>
|
||||
## [0.8.22](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.21...@ali/lowcode-demo@0.8.22) (2020-05-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.21"></a>
|
||||
## [0.8.21](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.20...@ali/lowcode-demo@0.8.21) (2020-05-15)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.20"></a>
|
||||
## [0.8.20](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.19...@ali/lowcode-demo@0.8.20) (2020-05-15)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.19"></a>
|
||||
## [0.8.19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.18...@ali/lowcode-demo@0.8.19) (2020-05-15)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.18"></a>
|
||||
## [0.8.18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.17...@ali/lowcode-demo@0.8.18) (2020-05-13)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.17"></a>
|
||||
## [0.8.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.16...@ali/lowcode-demo@0.8.17) (2020-05-13)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.16"></a>
|
||||
## [0.8.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.15...@ali/lowcode-demo@0.8.16) (2020-05-08)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.15"></a>
|
||||
## [0.8.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.14...@ali/lowcode-demo@0.8.15) (2020-05-08)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.14"></a>
|
||||
## [0.8.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.13...@ali/lowcode-demo@0.8.14) (2020-05-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 add history pane for vision demo ([3ce7079](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3ce7079))
|
||||
* 🐛 清理无用代码 ([015b58a](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/015b58a))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.8.13"></a>
|
||||
## [0.8.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.12...@ali/lowcode-demo@0.8.13) (2020-04-27)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.12"></a>
|
||||
## [0.8.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.11...@ali/lowcode-demo@0.8.12) (2020-04-27)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.11"></a>
|
||||
## [0.8.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.10...@ali/lowcode-demo@0.8.11) (2020-04-27)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.10"></a>
|
||||
## [0.8.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.9...@ali/lowcode-demo@0.8.10) (2020-04-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-demo
|
||||
|
||||
<a name="0.8.9"></a>
|
||||
## [0.8.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-demo@0.8.8...@ali/lowcode-demo@0.8.9) (2020-04-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* mixin-setter get all setter ([a5eb62d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a5eb62d))
|
||||
|
||||
|
||||
|
||||
|
||||
<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)
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{
|
||||
"entry": {
|
||||
"index": "src/index.ts",
|
||||
"react-simulator-renderer": "../react-simulator-renderer/src/index.ts",
|
||||
"preview": "src/preview.ts"
|
||||
"index": "src/index",
|
||||
"editor-preset-vision": "../editor-preset-vision/src/index.ts",
|
||||
"react-simulator-renderer": "../react-simulator-renderer/src/index.ts"
|
||||
},
|
||||
"vendor": false,
|
||||
"devServer": {
|
||||
@ -10,10 +10,12 @@
|
||||
},
|
||||
"publicPath": "/",
|
||||
"externals": {
|
||||
"react": "window.React",
|
||||
"react-dom": "window.ReactDOM",
|
||||
"prop-types": "window.PropTypes",
|
||||
"@alifd/next": "window.Next"
|
||||
"react": "var window.React",
|
||||
"react-dom": "var window.ReactDOM",
|
||||
"prop-types": "var window.PropTypes",
|
||||
"@alifd/next": "var window.Next",
|
||||
"@ali/visualengine": "var window.VisualEngine",
|
||||
"@ali/visualengine-utils": "var window.VisualEngineUtils"
|
||||
},
|
||||
"plugins": [
|
||||
[
|
||||
@ -35,4 +37,4 @@
|
||||
],
|
||||
"./build.plugin.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,22 @@
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
|
||||
|
||||
module.exports = ({ onGetWebpackConfig }) => {
|
||||
onGetWebpackConfig((config) => {
|
||||
config.resolve
|
||||
.plugin('tsconfigpaths')
|
||||
.use(TsconfigPathsPlugin, [{
|
||||
configFile: "./tsconfig.json"
|
||||
}]);
|
||||
config.resolve.plugin('tsconfigpaths').use(TsconfigPathsPlugin, [
|
||||
{
|
||||
configFile: './tsconfig.json',
|
||||
},
|
||||
]);
|
||||
|
||||
config
|
||||
// 定义插件名称
|
||||
.plugin('MonacoWebpackPlugin')
|
||||
// 第一项为具体插件,第二项为插件参数
|
||||
.use(new MonacoWebpackPlugin({
|
||||
languages:["typescript","css","json"]
|
||||
}), []);
|
||||
|
||||
config.plugins.delete('hot');
|
||||
config.devServer.hot(false);
|
||||
});
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
{
|
||||
"entry": {
|
||||
"lowcode-editor": "src/index.ts",
|
||||
"lowcode-preview": "src/preview.ts"
|
||||
"lowcode-editor": "src/vision/index.ts"
|
||||
},
|
||||
"vendor": false,
|
||||
"externals": {
|
||||
"react": "window.React",
|
||||
"react-dom": "window.ReactDOM",
|
||||
"prop-types": "window.PropTypes",
|
||||
"@ali/lowcode-globals": "window.LCEGlobals"
|
||||
"@ali/visualengine": "window.VisualEngine",
|
||||
"@ali/visualengine-utils": "window.VisualEngineUtils",
|
||||
"@ali/lowcode-editor-preset-general": "window.LowcodeEditor",
|
||||
"@ali/lowcode-editor-core": "window.LowcodeEditor",
|
||||
"@ali/lowcode-editor-skeleton": "window.LowcodeEditor",
|
||||
"@ali/lowcode-designer": "window.LowcodeEditor"
|
||||
},
|
||||
"minify": false,
|
||||
"sourcemap": true,
|
||||
|
||||
@ -1,39 +1,47 @@
|
||||
{
|
||||
"name": "@ali/lowcode-demo",
|
||||
"version": "0.8.8",
|
||||
"version": "0.8.33",
|
||||
"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-editor-core": "^0.8.19",
|
||||
"@ali/lowcode-editor-skeleton": "^0.8.29",
|
||||
"@ali/lowcode-plugin-components-pane": "^0.8.25",
|
||||
"@ali/lowcode-plugin-designer": "^0.9.23",
|
||||
"@ali/lowcode-plugin-event-bind-dialog": "^0.8.18",
|
||||
"@ali/lowcode-plugin-outline-pane": "^0.8.29",
|
||||
"@ali/lowcode-plugin-sample-logo": "^0.8.17",
|
||||
"@ali/lowcode-plugin-sample-preview": "^0.8.27",
|
||||
"@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",
|
||||
"@ali/lowcode-plugin-undo-redo": "^0.8.27",
|
||||
"@ali/lowcode-plugin-variable-bind-dialog": "^0.8.16",
|
||||
"@ali/lowcode-plugin-zh-en": "^0.8.20",
|
||||
"@ali/lowcode-react-renderer": "^0.8.12",
|
||||
"@ali/lowcode-runtime": "^0.8.16",
|
||||
"@ali/lowcode-utils": "^0.8.10",
|
||||
"@ali/ve-action-pane": "^4.7.0-beta.0",
|
||||
"@ali/ve-datapool-pane": "^6.4.3",
|
||||
"@ali/ve-history-pane": "4.0.0",
|
||||
"@ali/ve-i18n-manage-pane": "^4.3.0",
|
||||
"@ali/ve-i18n-pane": "^4.0.0-beta.0",
|
||||
"@ali/ve-page-history": "1.2.0",
|
||||
"@ali/ve-page-history-pane": "^5.0.0-beta.0",
|
||||
"@ali/ve-trunk-pane": "^5.1.0-beta.14",
|
||||
"@ali/vs-variable-setter": "^3.1.0",
|
||||
"@ali/vu-function-parser": "^2.5.0-beta.0",
|
||||
"@ali/vu-legao-design-fetch-context": "^1.0.3",
|
||||
"@alifd/next": "^1.19.12",
|
||||
"@alife/theme-lowcode-dark": "^0.1.0",
|
||||
"@alife/theme-lowcode-light": "^0.1.0",
|
||||
"compare-versions": "^3.0.1",
|
||||
"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",
|
||||
@ -41,6 +49,7 @@
|
||||
"build-plugin-fusion": "^0.1.0",
|
||||
"build-plugin-moment-locales": "^0.1.0",
|
||||
"build-plugin-react-app": "^1.1.2",
|
||||
"monaco-editor-webpack-plugin": "^1.9.0",
|
||||
"tsconfig-paths-webpack-plugin": "^3.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"packages": {
|
||||
"moment": {
|
||||
"packages": [
|
||||
{
|
||||
"package": "moment",
|
||||
"urls": ["https://g.alicdn.com/mylib/moment/2.24.0/min/moment.min.js"],
|
||||
"library": "moment"
|
||||
},
|
||||
"@alifd/next": {
|
||||
{
|
||||
"title": "fusion组件库",
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"urls": ["https://unpkg.antfin-inc.com/@alife/next@1.19.18/dist/next.js", "https://unpkg.antfin-inc.com/@alife/next@1.19.18/dist/next.css"],
|
||||
"library": "Next"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"Page": {
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"componentName": "Page",
|
||||
"title": "页面",
|
||||
"configure": {
|
||||
@ -39,8 +39,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Div": {
|
||||
"componentName": "Div",
|
||||
{
|
||||
"componentName": "Card",
|
||||
"npm": {
|
||||
"package": "@alifd/next",
|
||||
"version": "1.19.18",
|
||||
"destructuring": true,
|
||||
"exportName": "Card"
|
||||
},
|
||||
"title": "容器",
|
||||
"configure": {
|
||||
"component": {
|
||||
@ -48,7 +54,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Button": {
|
||||
{
|
||||
"componentName": "Button",
|
||||
"title": "按钮",
|
||||
"devMode": "proCode",
|
||||
@ -147,7 +153,7 @@
|
||||
"propType": "node"
|
||||
}]
|
||||
},
|
||||
"Button.Group": {
|
||||
{
|
||||
"componentName": "Button.Group",
|
||||
"title": "按钮组",
|
||||
"devMode": "proCode",
|
||||
@ -186,7 +192,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Input": {
|
||||
{
|
||||
"componentName": "Input",
|
||||
"title": "输入框",
|
||||
"devMode": "proCode",
|
||||
@ -197,6 +203,10 @@
|
||||
"exportName": "Input"
|
||||
},
|
||||
"props": [{
|
||||
"name": "value",
|
||||
"propType": "string",
|
||||
"description": ""
|
||||
},{
|
||||
"name": "label",
|
||||
"propType": "node",
|
||||
"description": "label"
|
||||
@ -300,7 +310,7 @@
|
||||
"description": "预览态模式下渲染的内容\n@param {number} value 评分值"
|
||||
}]
|
||||
},
|
||||
"Form": {
|
||||
{
|
||||
"componentName": "Form",
|
||||
"title": "表单容器",
|
||||
"devMode": "proCode",
|
||||
@ -423,7 +433,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Form.Item": {
|
||||
{
|
||||
"componentName": "Form.Item",
|
||||
"title": "表单项",
|
||||
"devMode": "proCode",
|
||||
@ -677,7 +687,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"NumberPicker": {
|
||||
{
|
||||
"componentName": "NumberPicker",
|
||||
"title": "数字输入",
|
||||
"devMode": "proCode",
|
||||
@ -829,7 +839,7 @@
|
||||
"description": "预设屏幕宽度"
|
||||
}]
|
||||
},
|
||||
"Select": {
|
||||
{
|
||||
"componentName": "Select",
|
||||
"title": "下拉",
|
||||
"devMode": "proCode",
|
||||
@ -1053,6 +1063,14 @@
|
||||
"name": "maxTagCount",
|
||||
"title": "最多显示多少个 tag",
|
||||
"setter": "ExpressionSetter"
|
||||
}, {
|
||||
"name": "color",
|
||||
"title": "颜色选择",
|
||||
"setter": "ColorSetter"
|
||||
}, {
|
||||
"name": "json",
|
||||
"title": "JSON设置",
|
||||
"setter": "JsonSetter"
|
||||
}, {
|
||||
"name": "MixinSetter",
|
||||
"placeholder": "混合",
|
||||
@ -1081,11 +1099,14 @@
|
||||
}, {
|
||||
"label": "左",
|
||||
"value": "l"
|
||||
}]
|
||||
}],
|
||||
"defaultValue": "l"
|
||||
}
|
||||
}, {
|
||||
"name": "NumberSetter",
|
||||
"props": {}
|
||||
"props": {
|
||||
"defaultValue": 5
|
||||
}
|
||||
}, {
|
||||
"name": "BoolSetter",
|
||||
"props": {}
|
||||
@ -1450,7 +1471,7 @@
|
||||
}]
|
||||
}
|
||||
},
|
||||
"Select.Option": {
|
||||
{
|
||||
"componentName": "Select.Option",
|
||||
"title": "选择项",
|
||||
"devMode": "proCode",
|
||||
@ -1485,14 +1506,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
"componentList": [{
|
||||
"title": "基础",
|
||||
"icon": "",
|
||||
"children": [{
|
||||
"componentName": "Button",
|
||||
"title": "按钮",
|
||||
"icon": "",
|
||||
"icon": "add",
|
||||
"package": "@alife/next",
|
||||
"library": "Next",
|
||||
"snippets": [{
|
||||
@ -1521,7 +1542,8 @@
|
||||
"schema": {
|
||||
"componentName": "Button",
|
||||
"props": {
|
||||
"type": "normal"
|
||||
"type": "normal",
|
||||
"value": "normal"
|
||||
},
|
||||
"children": "normal"
|
||||
}
|
||||
@ -1577,7 +1599,7 @@
|
||||
"title": "其他",
|
||||
"icon": "",
|
||||
"children": [{
|
||||
"componentName": "Div",
|
||||
"componentName": "Card",
|
||||
"library": "Next",
|
||||
"title": "容器",
|
||||
"icon": "",
|
||||
@ -1585,7 +1607,7 @@
|
||||
"title": "默认",
|
||||
"screenshot": "",
|
||||
"schema": {
|
||||
"componentName": "Div",
|
||||
"componentName": "Card",
|
||||
"props": {}
|
||||
}
|
||||
}]
|
||||
|
||||
@ -4,18 +4,71 @@
|
||||
<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>
|
||||
<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>
|
||||
React.PropTypes = PropTypes;
|
||||
</script>
|
||||
<script src="https://g.alicdn.com/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js"></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">
|
||||
<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="/css/editor-preset-vision.css" />
|
||||
<script>
|
||||
window.pageConfig = {
|
||||
env: 'release',
|
||||
locale: 'zh_CN',
|
||||
pageType: 'single',
|
||||
deviceType: 'web',
|
||||
appName: '基础包管理后台',
|
||||
appType: 'legao_base_packages',
|
||||
templateType: '',
|
||||
pageId: 'FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V',
|
||||
slug: 'test',
|
||||
appMode: 'back',
|
||||
isAppAdmin: 'y',
|
||||
isSuperAdmin: 'n',
|
||||
isBetaDeveloper: 'n',
|
||||
formType: 'display',
|
||||
title: { en_US: '测试', type: 'i18n', zh_CN: '测试' },
|
||||
urlPrefix: 'https://go.alibaba-inc.com',
|
||||
APIUrlPrefix: 'https://go.alibaba-inc.com',
|
||||
devVersion: '0.1.0', // 这个是子应用的变更 id
|
||||
subAppType: '0.1.0',
|
||||
appKey: 'legao_base_packages',
|
||||
RE_VERSION: '7.1.1',
|
||||
appSource: '',
|
||||
isDomainDefault: 'n',
|
||||
useReleaseBundle: 'n',
|
||||
isDomainPkg: 'n',
|
||||
medusaAppName: '',
|
||||
domainCode: 'kS6SyH',
|
||||
aecp: {
|
||||
mdcDomain: '',
|
||||
projectId: '',
|
||||
appCode: '',
|
||||
},
|
||||
designerConfigs: {},
|
||||
navConfig:
|
||||
'{"appName":{"en_US":"基础包管理后台","key":"","type":"i18n","zh_CN":"基础包管理后台"},"bgColor":"white","data":[{"children":[],"hidden":false,"icon":"","inner":true,"navUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","relateUuid":"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V","slug":"test","targetNew":false,"title":{"en_US":"测试","type":"i18n","zh_CN":"测试"}}],"isFixed":"y","isFold":"y","isFoldHorizontal":"n","languageChangeUrl":{"en_US":"/common/account/changeAccountLanguage.json","type":"i18n","zh_CN":"/common/account/changeAccountLanguage.json"},"layout":"auto","navStyle":"orange","navTheme":"light","openSubMode":false,"showAppTitle":true,"showCrumb":true,"showIcon":false,"showLanguageChange":true,"showNav":true,"showSearch":"n","singletons":{"FORM-3KYJN7RV-DIOD8LLK1WGQ89S7NHA92-QJVH497K-V":{"isFixed":"n","isFold":"n","isFoldHorizontal":"n","showAppTitle":false,"showCrumb":false,"showLanguageChange":false,"showNav":false,"showSearch":"n","singleton":false},"test":{"$ref":"$.singletons.FORM\\-3KYJN7RV\\-DIOD8LLK1WGQ89S7NHA92\\-QJVH497K\\-V"}},"type":"top_fold"}',
|
||||
historyType: 'HASH',
|
||||
isSinglePage: 'n',
|
||||
rhino: 'n',
|
||||
isMiniApp: '',
|
||||
taskId: '',
|
||||
appSchema: 'V5',
|
||||
openSubMode: 'n',
|
||||
};
|
||||
window.g_config = {};
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="lce-container"></div>
|
||||
<!-- lowcode engine globals -->
|
||||
<script src="/js/editor-preset-vision.js"></script>
|
||||
<script src="https://dev.g.alicdn.com/vision/visualengine-utils/5.0.0/engine-utils.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
504
packages/demo/public/legao-assets.json
Normal file
504
packages/demo/public/legao-assets.json
Normal file
@ -0,0 +1,504 @@
|
||||
{
|
||||
"externals": [
|
||||
{
|
||||
"urls": ["//g.alicdn.com/platform/c/react/16.5.2/react.min.js"],
|
||||
"library": "React",
|
||||
"name": "react",
|
||||
"version": "16.5.2"
|
||||
},
|
||||
{
|
||||
"urls": ["//g.alicdn.com/platform/c/react-dom/16.5.2/react-dom.min.js"],
|
||||
"library": "ReactDOM",
|
||||
"name": "react-dom",
|
||||
"version": "16.12.0"
|
||||
},
|
||||
{
|
||||
"urls": ["//g.alicdn.com/platform/c/prop-types/15.6.2/prop-types.js"],
|
||||
"library": "PropTypes",
|
||||
"name": "prop-types",
|
||||
"version": "15.6.2"
|
||||
},
|
||||
{ "library": "ReactRouter", "name": "react-router" },
|
||||
{ "library": "ReactRouterDOM", "name": "react-router-dom" },
|
||||
{ "library": "Babel", "name": "babel-standalone" },
|
||||
{ "library": "Recore", "name": "@ali/recore" },
|
||||
{
|
||||
"urls": ["https://g.alicdn.com/code/lib/moment.js/2.24.0/moment-with-locales.min.js"],
|
||||
"library": "moment",
|
||||
"name": "moment",
|
||||
"version": "2.24.0"
|
||||
},
|
||||
{
|
||||
"urls": ["https://g.alicdn.com/platform/c/??react15-polyfill/0.0.1/dist/index.js,lodash/4.6.1/lodash.min.js,immutable/3.7.6/dist/immutable.min.js,natty-storage/2.0.2/dist/natty-storage.min.js,natty-fetch/2.6.0/dist/natty-fetch.pc.min.js,tinymce/4.2.5/tinymce-full.js"],
|
||||
"library": "nattyFetch",
|
||||
"name": "natty-fetch",
|
||||
"version": "2.24.0"
|
||||
},
|
||||
{ "library": "VisualEngine", "name": "engine" },
|
||||
{ "library": "VisualEngine", "name": "visualengine" },
|
||||
{ "library": "VisualEngine", "name": "@ali/visualengine" },
|
||||
{ "library": "VisualEngineUtils", "name": "engine-utils" },
|
||||
{ "library": "VisualEngineUtils", "name": "@ali/visualengine-utils" },
|
||||
{ "library": "VisualEngine.ui.Popup", "name": "@ali/ve-popups" },
|
||||
{ "library": "VisualEngineUtils.FieldControl", "name": "@ali/ve-field" },
|
||||
{ "library": "VisualEngineUtils.BoolControl", "name": "@ali/ve-bool-control" },
|
||||
{ "library": "VisualEngineUtils.ChoiceControl", "name": "@ali/ve-choice-control" },
|
||||
{ "library": "VisualEngineUtils.ColorControl", "name": "@ali/ve-color-control" },
|
||||
{ "library": "VisualEngineUtils.DateControl", "name": "@ali/ve-date-control" },
|
||||
{ "library": "VisualEngineUtils.I18nControl", "name": "@ali/ve-i18n-control" },
|
||||
{ "library": "VisualEngineUtils.NumberControl", "name": "@ali/ve-number-control" },
|
||||
{ "library": "VisualEngineUtils.SelectControl", "name": "@ali/ve-select-control" },
|
||||
{ "library": "VisualEngineUtils.SortableControl", "name": "@ali/ve-sortable" },
|
||||
{ "library": "VisualEngineUtils.TextControl", "name": "@ali/ve-text-control" },
|
||||
{ "library": "VisualEngineUtils.ImageControl", "name": "@ali/ve-image-control" },
|
||||
{ "library": "VisualEngineUtils.SearchControl", "name": "@ali/ve-search-control" },
|
||||
{ "library": "VisualEngineUtils.BoolSetter", "name": "@ali/vs-bool" },
|
||||
{ "library": "VisualEngineUtils.ChoiceSetter", "name": "@ali/vs-choice" },
|
||||
{ "library": "VisualEngineUtils.CodeSetter", "name": "@ali/vs-code" },
|
||||
{ "library": "VisualEngineUtils.ColorSetter", "name": "@ali/vs-color" },
|
||||
{ "library": "VisualEngineUtils.DateSetter", "name": "@ali/vs-date" },
|
||||
{ "library": "VisualEngineUtils.I18nSetter", "name": "@ali/vs-i18n" },
|
||||
{ "library": "VisualEngineUtils.JsonSetter", "name": "@ali/vs-json" },
|
||||
{ "library": "VisualEngineUtils.ListSetter", "name": "@ali/vs-list" },
|
||||
{ "library": "VisualEngineUtils.NumberSetter", "name": "@ali/vs-number" },
|
||||
{ "library": "VisualEngineUtils.OptionsSetter", "name": "@ali/vs-options" },
|
||||
{ "library": "VisualEngineUtils.SelectSetter", "name": "@ali/vs-select" },
|
||||
{ "library": "VisualEngineUtils.TextSetter", "name": "@ali/vs-text" },
|
||||
{ "library": "VisualEngineUtils.ValidationSetter", "name": "@ali/vs-validation" },
|
||||
{ "library": "VisualEngineUtils.ImageSetter", "name": "@ali/vs-image" },
|
||||
{ "library": "VisualEngineUtils.StyleSetter", "name": "@ali/vs-style" },
|
||||
{ "library": "VisualEngineUtils.EventSetter", "name": "@ali/vs-event" },
|
||||
{ "library": "RenderEngine", "name": "@ali/render-engine" },
|
||||
{ "library": "Highcharts", "name": "highcharts" },
|
||||
{ "library": "Object", "name": "highcharts-more" },
|
||||
{ "library": "Highcharts && window.Highcharts.map", "name": "highcharts/highmaps" },
|
||||
{ "library": "jQuery", "name": "$" },
|
||||
{ "library": "jQuery", "name": "jquery" },
|
||||
{ "library": "_", "name": "lodash" },
|
||||
{ "library": "nattyFetch", "name": "natty-fetch" },
|
||||
{ "library": "nattyFetch", "name": "natty-fetch/dist/natty-fetch.pc" },
|
||||
{ "library": "nattyFetch", "name": "natty-fetch/dist/natty-fetch" },
|
||||
{ "library": "nattyStorage", "name": "natty-storage" },
|
||||
{ "library": "Rax", "name": "rax" }
|
||||
],
|
||||
"systemType": "",
|
||||
"appKey": "legao_base_packages",
|
||||
"componentDependencies": [
|
||||
{
|
||||
"prototypeConfigsUrl": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-div/1.0.1/proto.c54985f.js"],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcDiv",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-div/1.0.1/view.f31fe6d.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-div/1.0.1/view.d3df802.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-div",
|
||||
"version": "1.0.1"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.1.12/proto.611ab53.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.1.12/proto.5b7b3d3.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcDeep",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/view.03e2bef.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/view.e380202.js",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/view.mobile.03e2bef.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/view.mobile.4c4a443.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-deep",
|
||||
"version": "2.0.11"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.3/proto.81cf560.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.3/proto.5de342b.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcShell",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.3/view.81cf560.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-shell/1.5.3/view.3ef1990.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-shell",
|
||||
"version": "1.5.3"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/proto.0e43387.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/proto.0bda625.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcSlot",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/view.0e43387.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-slot/2.0.1/view.890474e.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-slot",
|
||||
"version": "2.0.1"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.0/proto.595bd91.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.0/proto.7afa924.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcText",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.0/view.764bd38.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.0/view.0dcac71.js",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-text/4.0.0/view.mobile.8a20311.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-text",
|
||||
"version": "4.0.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/proto.4828821.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/proto.dd97364.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcLink",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/view.387943c.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/view.ec70dd9.js",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/view.mobile.387943c.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link/5.1.1/view.mobile.bc72f32.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-link",
|
||||
"version": "5.1.1"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link-block/5.1.0/proto.b486b90.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcLinkBlock",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link-block/5.1.0/view.82ef4b0.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link-block/5.1.0/view.51d10d6.js",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link-block/5.1.0/view.mobile.82ef4b0.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-link-block/5.1.0/view.mobile.d608862.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-link-block",
|
||||
"version": "5.1.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-html/2.0.0/proto.8b5fefc.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-html/2.0.0/proto.0d2716f.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcHtml",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-html/2.0.0/view.0e43387.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-html/2.0.0/view.d3ef287.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-html",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-iframe/3.0.2/proto.6c9d90a.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-iframe/3.0.2/proto.c03e93e.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcIframe",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-iframe/3.0.2/view.6c9d90a.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-iframe/3.0.2/view.5bdba85.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-iframe",
|
||||
"version": "3.0.2"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-jsx/2.0.0/proto.9419927.js"],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcJsx",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-jsx/2.0.0/view.133d01c.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-jsx",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/proto.3f91095.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/proto.fa33aff.js"
|
||||
],
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVcMarkdown",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/view.3f91095.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-markdown/2.0.0/view.288bb26.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vc-markdown",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliDeepLegaoComponentImport",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/deep-legao-component-import/0.3.0/main.47a28d7.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/deep-legao-component-import/0.3.0/main.0751f12.js"
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"snippets": [
|
||||
{
|
||||
"schema": {
|
||||
"componentName": "LegaoComponentImport",
|
||||
"props": { "urlPrefix": "https://go.alibaba-inc.com/", "scene": "editConfig" }
|
||||
},
|
||||
"code": "<LegaoComponentImport scene=\"editConfig\" urlPrefix=\"https://go.alibaba-inc.com/\" />",
|
||||
"screenshot": "https://tianshu.alicdn.com/a6115d32-ec32-4d32-bf94-f24aace23ffa.png"
|
||||
}
|
||||
],
|
||||
"componentName": "LegaoComponentImport",
|
||||
"screenshot": "https://tianshu.alicdn.com/a6115d32-ec32-4d32-bf94-f24aace23ffa.png",
|
||||
"configure": {
|
||||
"component": {},
|
||||
"props": [
|
||||
{ "name": "onFinish", "title": "onFinish", "setter": "Function" },
|
||||
{ "name": "scene", "title": "scene", "setter": "Input" },
|
||||
{ "name": "componentInfo", "title": "componentInfo", "setter": "Object" },
|
||||
{ "name": "urlPrefix", "title": "urlPrefix", "setter": "Input" },
|
||||
{ "name": "getTicket", "title": "getTicket", "setter": "Function" },
|
||||
{ "name": "mode", "title": "mode", "setter": "Input" },
|
||||
{ "name": "height", "title": "height", "setter": "Number" },
|
||||
{ "name": "configListType", "title": "configListType", "setter": "Input" }
|
||||
]
|
||||
},
|
||||
"category": "自定义"
|
||||
}
|
||||
],
|
||||
"packageName": "@ali/deep-legao-component-import",
|
||||
"version": "0.3.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliReactCodeToImage",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/react-code-to-image/0.0.13/main.5ea90fb.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/react-code-to-image/0.0.13/main.08ab636.js"
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"snippets": [
|
||||
{
|
||||
"schema": { "componentName": "AliReactCodeToImage", "props": {} },
|
||||
"code": "<AliReactCodeToImage/>",
|
||||
"label": "react code to image",
|
||||
"screenshot": "https://tianshu.alicdn.com/958192c1-1d1a-4186-8438-63c80cb04fb3.png"
|
||||
}
|
||||
],
|
||||
"componentName": "AliReactCodeToImage",
|
||||
"screenshot": "https://tianshu.alicdn.com/958192c1-1d1a-4186-8438-63c80cb04fb3.png",
|
||||
"configure": {
|
||||
"component": {},
|
||||
"props": [
|
||||
{ "name": "library", "title": "library", "setter": "Input" },
|
||||
{ "name": "assets", "title": "assets", "setter": "Object" },
|
||||
{ "name": "initCode", "title": "initCode", "setter": "Input" },
|
||||
{ "name": "showEditor", "title": "showEditor", "setter": "Switch" },
|
||||
{ "name": "onRender", "title": "onRender", "setter": "Function" },
|
||||
{ "name": "onUploaded", "title": "onUploaded", "setter": "Function" },
|
||||
{ "name": "upload", "title": "upload", "setter": "Input" },
|
||||
{ "name": "showPreview", "title": "showPreview", "setter": "Switch" },
|
||||
{ "name": "builtInReact", "title": "builtInReact", "setter": "Switch" },
|
||||
{ "name": "builtInBabel", "title": "builtInBabel", "setter": "Switch" },
|
||||
{ "name": "style", "title": "style", "setter": "Input" },
|
||||
{ "name": "autoRender", "title": "autoRender", "setter": "Switch" },
|
||||
{ "name": "delay", "title": "delay", "setter": "Number" },
|
||||
{ "name": "autoUpload", "title": "autoUpload", "setter": "Switch" },
|
||||
{ "name": "noUI", "title": "noUI", "setter": "Switch" }
|
||||
]
|
||||
},
|
||||
"title": "react code to image",
|
||||
"category": "自定义"
|
||||
}
|
||||
],
|
||||
"packageName": "@ali/react-code-to-image",
|
||||
"version": "0.0.13"
|
||||
}
|
||||
],
|
||||
"utilsDependencies": [
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuFormatter",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-formatter/2.0.0/main.e75ff20.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-formatter",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuFusion",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-fusion/2.0.0/main.01f2f51.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-fusion",
|
||||
"version": "2.0.0"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuToolkit",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-toolkit/1.0.4/main.96fb938.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-toolkit",
|
||||
"version": "1.0.4"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuLegaoBuiltin",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-legao-builtin/1.2.2/main.2178271.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-legao-builtin",
|
||||
"version": "1.2.2"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuDataSource",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-dataSource/1.0.3/main.c153335.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-dataSource",
|
||||
"version": "1.0.3"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuRouter",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-router/1.2.1/main.5a856a4.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-router/1.2.1/main.6f0b6b1.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-router",
|
||||
"version": "1.2.1"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuRouterSpa",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-router-spa/1.3.7/main.c231469.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-router-spa/1.3.7/main.756e5a0.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-router-spa",
|
||||
"version": "1.3.7"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuSpm",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-spm/1.1.11/main.0495881.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-spm",
|
||||
"version": "1.1.11"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuSwitchSchema",
|
||||
"urls": [
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-switch-schema/1.0.7/main.1d9ec8c.css",
|
||||
"https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-switch-schema/1.0.7/main.70ec614.js"
|
||||
],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-switch-schema",
|
||||
"version": "1.0.7"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuLegaoBuiltin",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-legao-builtin/1.0.5/main.0ebe6a1.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-legao-builtin",
|
||||
"version": "1.0.5"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVuDataSource",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vu-dataSource/1.0.2/main.62e0289.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vu-dataSource",
|
||||
"version": "1.0.2"
|
||||
}
|
||||
],
|
||||
"otherDependencies": [
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "MyBabel",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/my-babel/0.9.6/main.8bd0181.js"],
|
||||
"components": null,
|
||||
"packageName": "my-babel",
|
||||
"version": "0.9.6"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVmRouter",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vm-router/1.0.8/main.115bf4f.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vm-router",
|
||||
"version": "1.0.8"
|
||||
},
|
||||
{
|
||||
"prototypeConfigsUrl": null,
|
||||
"prototypeViewsUrl": null,
|
||||
"alias": "",
|
||||
"library": "AliVmSchemaNav",
|
||||
"urls": ["https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vm-schema-nav/1.0.0/main.711344e.js"],
|
||||
"components": null,
|
||||
"packageName": "@ali/vm-schema-nav",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,12 +1,6 @@
|
||||
{
|
||||
"componentName": "Page",
|
||||
"fileName": "test",
|
||||
"dataSource": {
|
||||
"list": []
|
||||
},
|
||||
"state": {
|
||||
"text": "outter"
|
||||
},
|
||||
"id": "node_1",
|
||||
"props": {
|
||||
"ref": "outterView",
|
||||
"autoLoading": true,
|
||||
@ -14,97 +8,884 @@
|
||||
"padding": 20
|
||||
}
|
||||
},
|
||||
"children": [{
|
||||
"componentName": "Form",
|
||||
"props": {
|
||||
"labelCol": 3,
|
||||
"style": {},
|
||||
"ref": "testForm"
|
||||
},
|
||||
"children": [{
|
||||
"componentName": "Form.Item",
|
||||
"fileName": "test",
|
||||
"dataSource": {
|
||||
"list": []
|
||||
},
|
||||
"state": {
|
||||
"text": "outter",
|
||||
"abc": [
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Steps",
|
||||
"id": "node_1i",
|
||||
"props": {
|
||||
"label": "姓名:",
|
||||
"name": "name",
|
||||
"initValue": "李雷"
|
||||
},
|
||||
"children": [{
|
||||
"componentName": "Input",
|
||||
"props": {
|
||||
"placeholder": "请输入",
|
||||
"size": "medium",
|
||||
"style": {
|
||||
"width": 320
|
||||
"dataSource": [
|
||||
{
|
||||
"title": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": "报名"
|
||||
},
|
||||
"status": "",
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": "Open the refrigerator door"
|
||||
},
|
||||
"customSwitcher": false
|
||||
},
|
||||
{
|
||||
"title": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": "信息收集"
|
||||
},
|
||||
"status": "",
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": "Put the elephant in the refrigerator"
|
||||
},
|
||||
"customSwitcher": false
|
||||
},
|
||||
{
|
||||
"title": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": "审核"
|
||||
},
|
||||
"status": "",
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": "Close the refrigerator door"
|
||||
},
|
||||
"customSwitcher": false
|
||||
}
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"componentName": "Form.Item",
|
||||
],
|
||||
"current": 1,
|
||||
"shape": "circle",
|
||||
"direction": "horizontal",
|
||||
"labelPlacement": "vertical",
|
||||
"readOnly": false,
|
||||
"animation": true,
|
||||
"__style__": {},
|
||||
"fieldId": "steps_kadcb0ov"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Title",
|
||||
"id": "node_b",
|
||||
"props": {
|
||||
"label": "年龄:",
|
||||
"name": "age",
|
||||
"initValue": "22"
|
||||
},
|
||||
"children": [{
|
||||
"componentName": "NumberPicker",
|
||||
"props": {
|
||||
"size": "medium",
|
||||
"type": "normal"
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"componentName": "Form.Item",
|
||||
"text": "请填写以下人员信息表单",
|
||||
"type": "primary",
|
||||
"noDecoration": false,
|
||||
"__style__": {},
|
||||
"fieldId": "title_kadcb0nw"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Paragraph",
|
||||
"id": "node_e",
|
||||
"props": {
|
||||
"label": "职业:",
|
||||
"name": "profession"
|
||||
},
|
||||
"children": [{
|
||||
"componentName": "Select",
|
||||
"props": {
|
||||
"dataSource": [{
|
||||
"label": "教师",
|
||||
"value": "t"
|
||||
}, {
|
||||
"label": "医生",
|
||||
"value": "d"
|
||||
}, {
|
||||
"label": "歌手",
|
||||
"value": "s"
|
||||
}]
|
||||
}
|
||||
}]
|
||||
}, {
|
||||
"componentName": "Div",
|
||||
"content": "人最宝贵的是生命。它给予我们只有一次。人的一生应当这样度过:当他回首往事时不因虚度年华而悔恨,也不因碌碌无为而羞耻。这样在他临死的时侯就能够说:我已把我整个的生命和全部精力都献给最壮丽的事业——为人类的解放而斗争。",
|
||||
"size": "medium",
|
||||
"type": "long",
|
||||
"__style__": {},
|
||||
"fieldId": "paragraph_kadcb0nz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "ColumnsLayout",
|
||||
"id": "node_r",
|
||||
"props": {
|
||||
"style": {
|
||||
"textAlign": "center"
|
||||
}
|
||||
"layout": "6:6",
|
||||
"columnGap": "16px",
|
||||
"rowGap": "16px",
|
||||
"__style__": {
|
||||
"marginTop": "24px"
|
||||
},
|
||||
"fieldId": "columnsLayout_kadcb0ob"
|
||||
},
|
||||
"children": [{
|
||||
"componentName": "Button.Group",
|
||||
"props": {},
|
||||
"children": [{
|
||||
"componentName": "Button",
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Column",
|
||||
"id": "node_s",
|
||||
"props": {
|
||||
"type": "primary",
|
||||
"style": {
|
||||
"margin": "0 5px 0 5px"
|
||||
},
|
||||
"htmlType": "submit"
|
||||
"fieldId": "column_kadcb0o9",
|
||||
"__style__": {}
|
||||
},
|
||||
"children": "提交"
|
||||
}, {
|
||||
"componentName": "Button",
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Card",
|
||||
"id": "node_n",
|
||||
"props": {
|
||||
"title": "基本信息",
|
||||
"subTitle": {
|
||||
"type": "i18n",
|
||||
"zh_CN": "",
|
||||
"en_US": ""
|
||||
},
|
||||
"extra": {
|
||||
"type": "JSSlot",
|
||||
"params": null,
|
||||
"value": [
|
||||
{
|
||||
"componentName": "Icon",
|
||||
"id": "node_q",
|
||||
"props": {
|
||||
"type": {
|
||||
"useType": true,
|
||||
"baseType": "smile",
|
||||
"otherType": "smile"
|
||||
},
|
||||
"size": "medium",
|
||||
"__style__": {},
|
||||
"fieldId": "icon_kadcb0o8"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"showTitleBullet": true,
|
||||
"showHeadDivider": true,
|
||||
"dividerNoInset": false,
|
||||
"contentHeight": "",
|
||||
"__style__": {},
|
||||
"fieldId": "card_kadcb0o7"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "CardContent",
|
||||
"id": "node_o",
|
||||
"props": {},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Form",
|
||||
"id": "node_f",
|
||||
"props": {
|
||||
"labelAlign": "top",
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"autoValidate": true,
|
||||
"scrollToFirstError": true,
|
||||
"autoUnmount": true,
|
||||
"fieldOptions": {},
|
||||
"__style__": {
|
||||
"marginTop": "24px"
|
||||
},
|
||||
"fieldId": "form_kadcb0o5"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "TextField",
|
||||
"id": "node_g",
|
||||
"props": {
|
||||
"__category__": "form",
|
||||
"__useMediator": "value",
|
||||
"label": "姓名",
|
||||
"value": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"labelAlign": "top",
|
||||
"labelColSpan": 4,
|
||||
"labelColOffset": 0,
|
||||
"wrapperColSpan": 0,
|
||||
"wrapperColOffset": 0,
|
||||
"labelTextAlign": "right",
|
||||
"placeholder": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": "Please enter",
|
||||
"zh_CN": "请输入"
|
||||
},
|
||||
"tips": {
|
||||
"zh_CN": "",
|
||||
"en_US": "",
|
||||
"type": "i18n"
|
||||
},
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"labelTipsTypes": "none",
|
||||
"labelTipsIcon": "",
|
||||
"labelTipsText": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"htmlType": "input",
|
||||
"state": "",
|
||||
"rows": 4,
|
||||
"autoHeight": false,
|
||||
"hasClear": false,
|
||||
"trim": false,
|
||||
"autoFocus": false,
|
||||
"addonBefore": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"addonAfter": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"validation": [],
|
||||
"hasLimitHint": false,
|
||||
"cutString": false,
|
||||
"__style__": {},
|
||||
"fieldId": "textField_kadcb0o0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "RadioField",
|
||||
"id": "node_14",
|
||||
"props": {
|
||||
"__category__": "form",
|
||||
"__useMediator": "value",
|
||||
"label": "性别",
|
||||
"value": "",
|
||||
"labelAlign": "top",
|
||||
"labelColSpan": 4,
|
||||
"labelColOffset": 0,
|
||||
"wrapperColSpan": 0,
|
||||
"wrapperColOffset": 0,
|
||||
"labelTextAlign": "right",
|
||||
"tips": {
|
||||
"zh_CN": "",
|
||||
"en_US": "",
|
||||
"type": "i18n"
|
||||
},
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"labelTipsTypes": "none",
|
||||
"labelTipsIcon": "",
|
||||
"labelTipsText": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"shape": "default",
|
||||
"itemDirection": "hoz",
|
||||
"dataSource": [
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项一",
|
||||
"en_US": "Option 1",
|
||||
"type": "i18n",
|
||||
"use": "zh_CN"
|
||||
},
|
||||
"value": "1",
|
||||
"disable": false
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项二",
|
||||
"en_US": "Option 2",
|
||||
"type": "i18n",
|
||||
"use": "zh_CN"
|
||||
},
|
||||
"value": "2",
|
||||
"disable": false
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项三",
|
||||
"en_US": "Option 3",
|
||||
"type": "i18n",
|
||||
"use": "zh_CN"
|
||||
},
|
||||
"value": "3",
|
||||
"disable": true
|
||||
}
|
||||
],
|
||||
"validation": [],
|
||||
"__style__": {},
|
||||
"fieldId": "radioField_kadcb0ok"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "SelectField",
|
||||
"id": "node_h",
|
||||
"props": {
|
||||
"__category__": "form",
|
||||
"__useMediator": "value",
|
||||
"label": "学校",
|
||||
"value": "",
|
||||
"labelAlign": "top",
|
||||
"labelColSpan": 4,
|
||||
"labelColOffset": 0,
|
||||
"wrapperColSpan": 0,
|
||||
"wrapperColOffset": 0,
|
||||
"labelTextAlign": "right",
|
||||
"placeholder": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": "please select",
|
||||
"zh_CN": "请选择"
|
||||
},
|
||||
"tips": {
|
||||
"zh_CN": "",
|
||||
"en_US": "",
|
||||
"type": "i18n"
|
||||
},
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"labelTipsTypes": "none",
|
||||
"labelTipsIcon": "",
|
||||
"labelTipsText": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"mode": "single",
|
||||
"hasClear": false,
|
||||
"hasSelectAll": false,
|
||||
"showSearch": false,
|
||||
"filterLocal": true,
|
||||
"dataSource": [
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项一",
|
||||
"en_US": "Option 1",
|
||||
"type": "i18n"
|
||||
},
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项二",
|
||||
"en_US": "Option 2",
|
||||
"type": "i18n"
|
||||
},
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项三",
|
||||
"en_US": "Option 3",
|
||||
"type": "i18n"
|
||||
},
|
||||
"value": "3"
|
||||
}
|
||||
],
|
||||
"validation": [],
|
||||
"notFoundContent": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null
|
||||
},
|
||||
"hasArrow": true,
|
||||
"hasBorder": true,
|
||||
"autoWidth": true,
|
||||
"searchDelay": 300,
|
||||
"__style__": {},
|
||||
"fieldId": "select_kadcb0o1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Div",
|
||||
"id": "node_i",
|
||||
"props": {
|
||||
"behavior": "NORMAL",
|
||||
"__style__": {},
|
||||
"fieldId": "div_kadcb0o4"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Button",
|
||||
"id": "node_j",
|
||||
"props": {
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"en_US": "Ok",
|
||||
"zh_CN": "提交"
|
||||
},
|
||||
"type": "primary",
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"baseIcon": "",
|
||||
"otherIcon": "",
|
||||
"loading": false,
|
||||
"triggerEventsWhenLoading": false,
|
||||
"__style__": ":root {\n margin-right: 15px;\n}",
|
||||
"fieldId": "button_kadcb0o2",
|
||||
"onClick": {
|
||||
"type": "JSExpression",
|
||||
"value": "function onSubmit(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').submit(function(data, error) {\n if (data) {\n console.log(data);\n // 往后端提交数据,一般写法如下\n // this.dataSourceMap['xxx'].load(data).then(() => {\n // this.utils.toast({\n // type: 'success',\n // title: '提交成功'\n // });\n // });\n }\n });\n}",
|
||||
"extType": "function",
|
||||
"events": [
|
||||
{
|
||||
"name": "onClick",
|
||||
"params": {},
|
||||
"func": {
|
||||
"type": "js",
|
||||
"source": "function onSubmit(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').submit(function(data, error) {\n if (data) {\n console.log(data);\n // 往后端提交数据,一般写法如下\n // this.dataSourceMap['xxx'].load(data).then(() => {\n // this.utils.toast({\n // type: 'success',\n // title: '提交成功'\n // });\n // });\n }\n });\n}",
|
||||
"compiled": "function onSubmit(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').submit(function(data, error) {\n if (data) {\n console.log(data);\n // 往后端提交数据,一般写法如下\n // this.dataSourceMap['xxx'].load(data).then(() => {\n // this.utils.toast({\n // type: 'success',\n // title: '提交成功'\n // });\n // });\n }\n });\n}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Button",
|
||||
"id": "node_k",
|
||||
"props": {
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"en_US": "Reset",
|
||||
"zh_CN": "重置"
|
||||
},
|
||||
"type": "secondary",
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"baseIcon": "",
|
||||
"otherIcon": "",
|
||||
"loading": false,
|
||||
"triggerEventsWhenLoading": false,
|
||||
"__style__": {},
|
||||
"fieldId": "button_kadcb0o3",
|
||||
"onClick": {
|
||||
"type": "JSExpression",
|
||||
"value": "function onReset(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').reset();\n}",
|
||||
"extType": "function",
|
||||
"events": [
|
||||
{
|
||||
"name": "onClick",
|
||||
"params": {},
|
||||
"func": {
|
||||
"type": "js",
|
||||
"source": "function onReset(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').reset();\n}",
|
||||
"compiled": "function onReset(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').reset();\n}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentName": "Column",
|
||||
"id": "node_t",
|
||||
"props": {
|
||||
"type": "normal",
|
||||
"style": {
|
||||
"margin": "0 5px 0 5px"
|
||||
},
|
||||
"htmlType": "reset"
|
||||
"fieldId": "column_kadcb0oa",
|
||||
"__style__": {}
|
||||
},
|
||||
"children": "重置"
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Card",
|
||||
"id": "node_u",
|
||||
"props": {
|
||||
"title": {
|
||||
"type": "JSSlot",
|
||||
"params": null,
|
||||
"value": [
|
||||
{
|
||||
"componentName": "Icon",
|
||||
"id": "node_18",
|
||||
"props": {
|
||||
"type": {
|
||||
"useType": true,
|
||||
"baseType": "smile",
|
||||
"otherType": "smile"
|
||||
},
|
||||
"size": "medium",
|
||||
"__style__": {},
|
||||
"fieldId": "icon_kadcb0on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Link",
|
||||
"id": "node_19",
|
||||
"props": {
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": "link text",
|
||||
"zh_CN": "扩展信息"
|
||||
},
|
||||
"textOverflow": false,
|
||||
"link": {
|
||||
"type": "page",
|
||||
"page": null,
|
||||
"router": {
|
||||
"type": "JSExpression",
|
||||
"value": "this.utils.router"
|
||||
}
|
||||
},
|
||||
"__style__": {},
|
||||
"fieldId": "link_kadcb0oo"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"subTitle": {
|
||||
"type": "i18n",
|
||||
"zh_CN": "",
|
||||
"en_US": ""
|
||||
},
|
||||
"extra": {
|
||||
"type": "JSSlot",
|
||||
"params": null,
|
||||
"value": [
|
||||
{
|
||||
"componentName": "Icon",
|
||||
"id": "node_1a",
|
||||
"props": {
|
||||
"type": {
|
||||
"useType": true,
|
||||
"baseType": "smile",
|
||||
"otherType": "smile"
|
||||
},
|
||||
"size": "xl",
|
||||
"__style__": {},
|
||||
"fieldId": "icon_kadcb0op"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"showTitleBullet": true,
|
||||
"showHeadDivider": true,
|
||||
"dividerNoInset": false,
|
||||
"contentHeight": "",
|
||||
"__style__": {},
|
||||
"fieldId": "card_kadcb0oc"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "CardContent",
|
||||
"id": "node_v",
|
||||
"props": {},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Form",
|
||||
"id": "node_x",
|
||||
"props": {
|
||||
"labelAlign": "top",
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"autoValidate": true,
|
||||
"scrollToFirstError": true,
|
||||
"autoUnmount": true,
|
||||
"fieldOptions": {},
|
||||
"__style__": {
|
||||
"marginTop": "24px"
|
||||
},
|
||||
"fieldId": "form_kadcb0oi"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "TextField",
|
||||
"id": "node_y",
|
||||
"props": {
|
||||
"__category__": "form",
|
||||
"__useMediator": "value",
|
||||
"label": "职位",
|
||||
"value": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"labelAlign": "top",
|
||||
"labelColSpan": 4,
|
||||
"labelColOffset": 0,
|
||||
"wrapperColSpan": 0,
|
||||
"wrapperColOffset": 0,
|
||||
"labelTextAlign": "right",
|
||||
"placeholder": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": "Please enter",
|
||||
"zh_CN": "请输入"
|
||||
},
|
||||
"tips": {
|
||||
"zh_CN": "",
|
||||
"en_US": "",
|
||||
"type": "i18n"
|
||||
},
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"labelTipsTypes": "none",
|
||||
"labelTipsIcon": "",
|
||||
"labelTipsText": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"htmlType": "input",
|
||||
"state": "",
|
||||
"rows": 4,
|
||||
"autoHeight": false,
|
||||
"hasClear": false,
|
||||
"trim": false,
|
||||
"autoFocus": false,
|
||||
"addonBefore": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"addonAfter": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"validation": [],
|
||||
"hasLimitHint": false,
|
||||
"cutString": false,
|
||||
"__style__": {},
|
||||
"fieldId": "textField_kadcb0od"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "DateField",
|
||||
"id": "node_15",
|
||||
"props": {
|
||||
"__category__": "form",
|
||||
"__useMediator": "value",
|
||||
"label": "入职时间",
|
||||
"value": "",
|
||||
"labelAlign": "top",
|
||||
"labelColSpan": 4,
|
||||
"labelColOffset": 0,
|
||||
"wrapperColSpan": 0,
|
||||
"wrapperColOffset": 0,
|
||||
"labelTextAlign": "right",
|
||||
"placeholder": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": "please select",
|
||||
"zh_CN": "请选择"
|
||||
},
|
||||
"tips": {
|
||||
"zh_CN": "",
|
||||
"en_US": "",
|
||||
"type": "i18n"
|
||||
},
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"format": "YYYY-MM-DD",
|
||||
"returnType": "timestamp",
|
||||
"labelTipsTypes": "none",
|
||||
"labelTipsIcon": "",
|
||||
"labelTipsText": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"hasClear": true,
|
||||
"resetTime": false,
|
||||
"disabledDate": false,
|
||||
"validation": [],
|
||||
"__style__": {},
|
||||
"fieldId": "dateField_kadcb0ol"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "SelectField",
|
||||
"id": "node_z",
|
||||
"props": {
|
||||
"__category__": "form",
|
||||
"__useMediator": "value",
|
||||
"label": "下拉选择",
|
||||
"value": "",
|
||||
"labelAlign": "top",
|
||||
"labelColSpan": 4,
|
||||
"labelColOffset": 0,
|
||||
"wrapperColSpan": 0,
|
||||
"wrapperColOffset": 0,
|
||||
"labelTextAlign": "right",
|
||||
"placeholder": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": "please select",
|
||||
"zh_CN": "请选择"
|
||||
},
|
||||
"tips": {
|
||||
"zh_CN": "",
|
||||
"en_US": "",
|
||||
"type": "i18n"
|
||||
},
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"labelTipsTypes": "none",
|
||||
"labelTipsIcon": "",
|
||||
"labelTipsText": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null,
|
||||
"zh_CN": ""
|
||||
},
|
||||
"mode": "single",
|
||||
"hasClear": false,
|
||||
"hasSelectAll": false,
|
||||
"showSearch": false,
|
||||
"filterLocal": true,
|
||||
"dataSource": [
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项一",
|
||||
"en_US": "Option 1",
|
||||
"type": "i18n"
|
||||
},
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项二",
|
||||
"en_US": "Option 2",
|
||||
"type": "i18n"
|
||||
},
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"text": {
|
||||
"zh_CN": "选项三",
|
||||
"en_US": "Option 3",
|
||||
"type": "i18n"
|
||||
},
|
||||
"value": "3"
|
||||
}
|
||||
],
|
||||
"validation": [],
|
||||
"notFoundContent": {
|
||||
"type": "i18n",
|
||||
"use": "zh_CN",
|
||||
"en_US": null
|
||||
},
|
||||
"hasArrow": true,
|
||||
"hasBorder": true,
|
||||
"autoWidth": true,
|
||||
"searchDelay": 300,
|
||||
"__style__": {},
|
||||
"fieldId": "select_kadcb0oe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Div",
|
||||
"id": "node_10",
|
||||
"props": {
|
||||
"behavior": "NORMAL",
|
||||
"__style__": {},
|
||||
"fieldId": "div_kadcb0oh"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "Button",
|
||||
"id": "node_11",
|
||||
"props": {
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"en_US": "Ok",
|
||||
"zh_CN": "提交"
|
||||
},
|
||||
"type": "primary",
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"baseIcon": "",
|
||||
"otherIcon": "",
|
||||
"loading": false,
|
||||
"triggerEventsWhenLoading": false,
|
||||
"__style__": ":root {\n margin-right: 15px;\n}",
|
||||
"fieldId": "button_kadcb0of",
|
||||
"onClick": {
|
||||
"type": "JSExpression",
|
||||
"value": "function onSubmit(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').submit(function(data, error) {\n if (data) {\n console.log(data);\n // 往后端提交数据,一般写法如下\n // this.dataSourceMap['xxx'].load(data).then(() => {\n // this.utils.toast({\n // type: 'success',\n // title: '提交成功'\n // });\n // });\n }\n });\n}",
|
||||
"extType": "function",
|
||||
"events": [
|
||||
{
|
||||
"name": "onClick",
|
||||
"params": {},
|
||||
"func": {
|
||||
"type": "js",
|
||||
"source": "function onSubmit(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').submit(function(data, error) {\n if (data) {\n console.log(data);\n // 往后端提交数据,一般写法如下\n // this.dataSourceMap['xxx'].load(data).then(() => {\n // this.utils.toast({\n // type: 'success',\n // title: '提交成功'\n // });\n // });\n }\n });\n}",
|
||||
"compiled": "function onSubmit(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').submit(function(data, error) {\n if (data) {\n console.log(data);\n // 往后端提交数据,一般写法如下\n // this.dataSourceMap['xxx'].load(data).then(() => {\n // this.utils.toast({\n // type: 'success',\n // title: '提交成功'\n // });\n // });\n }\n });\n}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentName": "Button",
|
||||
"id": "node_12",
|
||||
"props": {
|
||||
"content": {
|
||||
"type": "i18n",
|
||||
"en_US": "Reset",
|
||||
"zh_CN": "重置"
|
||||
},
|
||||
"type": "secondary",
|
||||
"size": "medium",
|
||||
"behavior": "NORMAL",
|
||||
"baseIcon": "",
|
||||
"otherIcon": "",
|
||||
"loading": false,
|
||||
"triggerEventsWhenLoading": false,
|
||||
"__style__": {},
|
||||
"fieldId": "button_kadcb0og",
|
||||
"onClick": {
|
||||
"type": "JSExpression",
|
||||
"value": "function onReset(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').reset();\n}",
|
||||
"extType": "function",
|
||||
"events": [
|
||||
{
|
||||
"name": "onClick",
|
||||
"params": {},
|
||||
"func": {
|
||||
"type": "js",
|
||||
"source": "function onReset(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').reset();\n}",
|
||||
"compiled": "function onReset(){\n // 请将 fieldId 替换为表单容器的 fieldId\n this.$('fieldId').reset();\n}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,155 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -8,7 +8,7 @@ import Preview from './plugins/provider';
|
||||
app.registerRenderer(Renderer);
|
||||
|
||||
// 注册布局组件,可注册多个
|
||||
app.registerLayout('BasicLayout', BasicLayout);
|
||||
app.registerLayout(BasicLayout, { componentName: 'BasicLayout' });
|
||||
|
||||
// 注册页面 Loading
|
||||
app.registerLoading(FusionLoading);
|
||||
|
||||
21
packages/demo/src/editor/components.ts
Normal file
21
packages/demo/src/editor/components.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import logo from '@ali/lowcode-plugin-sample-logo';
|
||||
import samplePreview from '@ali/lowcode-plugin-sample-preview';
|
||||
//import undoRedo from '@ali/lowcode-plugin-undo-redo';
|
||||
import componentsPane from '@ali/lowcode-plugin-components-pane';
|
||||
import outline, { OutlinePane } from '@ali/lowcode-plugin-outline-pane';
|
||||
import zhEn from '@ali/lowcode-plugin-zh-en';
|
||||
import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog';
|
||||
import variableBindDialog from '@ali/lowcode-plugin-variable-bind-dialog';
|
||||
import sourceEditor from '@ali/lowcode-plugin-source-editor';
|
||||
|
||||
export default {
|
||||
logo,
|
||||
samplePreview,
|
||||
//undoRedo,
|
||||
componentsPane,
|
||||
outline,
|
||||
zhEn,
|
||||
eventBindDialog,
|
||||
variableBindDialog,
|
||||
sourceEditor,
|
||||
}
|
||||
109
packages/demo/src/editor/config.js
Normal file
109
packages/demo/src/editor/config.js
Normal file
@ -0,0 +1,109 @@
|
||||
export default {
|
||||
plugins: {
|
||||
topArea: [
|
||||
{
|
||||
pluginKey: 'logo',
|
||||
type: 'Custom',
|
||||
props: {
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
pluginProps: {
|
||||
logo: 'https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png',
|
||||
href: '/',
|
||||
},
|
||||
},
|
||||
/*
|
||||
{
|
||||
pluginKey: 'undoRedo',
|
||||
type: 'Custom',
|
||||
props: {
|
||||
align: 'right',
|
||||
width: 88,
|
||||
},
|
||||
},
|
||||
{
|
||||
pluginKey: 'divider',
|
||||
type: 'Divider',
|
||||
props: {
|
||||
align: 'right',
|
||||
},
|
||||
},*/
|
||||
{
|
||||
pluginKey: 'samplePreview',
|
||||
type: 'Custom',
|
||||
props: {
|
||||
align: 'right',
|
||||
width: 64,
|
||||
},
|
||||
},
|
||||
],
|
||||
leftArea: [
|
||||
{
|
||||
pluginKey: 'componentsPane',
|
||||
type: 'PanelIcon',
|
||||
props: {
|
||||
align: 'top',
|
||||
icon: 'zujianku',
|
||||
description: '组件库',
|
||||
},
|
||||
pluginProps: {},
|
||||
},
|
||||
{
|
||||
pluginKey: 'outline',
|
||||
type: 'PanelIcon',
|
||||
props: {
|
||||
align: 'top',
|
||||
icon: 'shuxingkongjian',
|
||||
description: '大纲树',
|
||||
},
|
||||
pluginProps: {},
|
||||
},
|
||||
{
|
||||
pluginKey: 'sourceEditor',
|
||||
type: 'PanelIcon',
|
||||
props: {
|
||||
align: 'top',
|
||||
icon: 'wenjian',
|
||||
description: '资源面板',
|
||||
panelProps: {
|
||||
floatable: true,
|
||||
height: 300,
|
||||
help: undefined,
|
||||
hideTitleBar: true,
|
||||
maxHeight: 800,
|
||||
maxWidth: 1200,
|
||||
title: "动作面板",
|
||||
width: 600
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
pluginKey: 'zhEn',
|
||||
type: 'Custom',
|
||||
props: {
|
||||
align: 'bottom',
|
||||
},
|
||||
pluginProps: {},
|
||||
},
|
||||
],
|
||||
centerArea: [
|
||||
{
|
||||
pluginKey: 'eventBindDialog',
|
||||
},
|
||||
{
|
||||
pluginKey: 'variableBindDialog',
|
||||
},
|
||||
]
|
||||
},
|
||||
shortCuts: [],
|
||||
lifeCycles: {
|
||||
init: async function init(editor) {
|
||||
const assets = await editor.utils.get('./assets.json');
|
||||
editor.set('assets', assets);
|
||||
|
||||
const schema = await editor.utils.get('./schema.json');
|
||||
editor.set('schema', schema);
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -1,22 +0,0 @@
|
||||
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
|
||||
};
|
||||
@ -1,3 +0,0 @@
|
||||
export default {
|
||||
"namespace": "page"
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export default {};
|
||||
@ -1,10 +0,0 @@
|
||||
import en_us from './en-US';
|
||||
import zh_cn from './zh-CN';
|
||||
import zh_tw from './zh-TW';
|
||||
import ja_jp from './ja-JP';
|
||||
export default {
|
||||
'en-US': en_us,
|
||||
'zh-CN': zh_cn,
|
||||
'zh-TW': zh_tw,
|
||||
'ja-JP': ja_jp
|
||||
};
|
||||
@ -1 +0,0 @@
|
||||
export default {};
|
||||
@ -1 +0,0 @@
|
||||
export default {};
|
||||
@ -1 +0,0 @@
|
||||
export default {};
|
||||
@ -1,140 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1,3 +0,0 @@
|
||||
export default {
|
||||
|
||||
};
|
||||
@ -5,3 +5,25 @@ body {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
body, #lce-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
-webkit-text-size-adjust: none;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html {
|
||||
min-width: 1024px;
|
||||
}
|
||||
|
||||
@ -1,20 +1,9 @@
|
||||
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 { render } from 'react-dom';
|
||||
import GeneralWorkbench, { editor } from '../../../editor-preset-general/src';
|
||||
import config from './config';
|
||||
import components from './components';
|
||||
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);
|
||||
render(<GeneralWorkbench config={config} components={components} />, LCE_CONTAINER);
|
||||
|
||||
@ -1 +1 @@
|
||||
import './editor';
|
||||
import './vision';
|
||||
|
||||
517
packages/demo/src/vision/index.ts
Normal file
517
packages/demo/src/vision/index.ts
Normal file
@ -0,0 +1,517 @@
|
||||
/* eslint-disable */
|
||||
import { createElement } from 'react';
|
||||
import { Button } from '@alifd/next';
|
||||
import Engine, { Panes, Prototype } from '@ali/visualengine';
|
||||
import { ActionUtil as actionUtil } from '@ali/visualengine-utils';
|
||||
import getTrunkPane from '@ali/ve-trunk-pane';
|
||||
import DatapoolPane from '@ali/ve-datapool-pane';
|
||||
import PageHistoryManager from '@ali/ve-page-history';
|
||||
import HistoryPane from '@ali/ve-history-pane';
|
||||
import PageHistoryPane from '@ali/ve-page-history-pane';
|
||||
// import I18nPane from '@ali/ve-i18n-pane';
|
||||
import I18nManagePane from '@ali/ve-i18n-manage-pane';
|
||||
import ActionPane from '@ali/ve-action-pane';
|
||||
import SourceEditor from '@ali/lowcode-plugin-source-editor';
|
||||
import fetchContext from '@ali/vu-legao-design-fetch-context';
|
||||
import EventBindDialog from '@ali/lowcode-plugin-event-bind-dialog';
|
||||
import loadUrls from './loader';
|
||||
import { upgradeAssetsBundle } from './upgrade-assets';
|
||||
import { isCSSUrl } from '@ali/lowcode-utils';
|
||||
import VariableSetter from '@ali/vs-variable-setter';
|
||||
import _isArray from "lodash/isArray";
|
||||
import _isObject from "lodash/isObject";
|
||||
import _get from 'lodash/get';
|
||||
import funcParser from '@ali/vu-function-parser';
|
||||
import {
|
||||
NumberSetter,
|
||||
BoolSetter,
|
||||
ChoiceSetter,
|
||||
CodeSetter,
|
||||
ColorSetter,
|
||||
DateSetter,
|
||||
I18nSetter,
|
||||
JsonSetter,
|
||||
ListSetter,
|
||||
SelectSetter,
|
||||
OptionsSetter,
|
||||
TextSetter,
|
||||
ValidationSetter,
|
||||
ActionSetter,
|
||||
} from '@ali/visualengine-utils';
|
||||
|
||||
const { editor, skeleton, context, HOOKS, Trunk } = Engine;
|
||||
|
||||
Trunk.registerSetter('Input', TextSetter);
|
||||
Trunk.registerSetter('StringSetter', TextSetter);
|
||||
Trunk.registerSetter('TextArea', TextSetter);
|
||||
Trunk.registerSetter('Object', JsonSetter);
|
||||
Trunk.registerSetter('Function', ActionSetter);
|
||||
Trunk.registerSetter('Node', CodeSetter);
|
||||
Trunk.registerSetter('Mixin', CodeSetter);
|
||||
Trunk.registerSetter('Expression', CodeSetter);
|
||||
Trunk.registerSetter('List', ListSetter);
|
||||
Trunk.registerSetter('Switch', BoolSetter);
|
||||
Trunk.registerSetter('Number', NumberSetter);
|
||||
Trunk.registerSetter('Select', SelectSetter);
|
||||
|
||||
Trunk.registerSetter('ActionSetter', ActionSetter);
|
||||
Trunk.registerSetter('BoolSetter', BoolSetter);
|
||||
Trunk.registerSetter('ChoiceSetter', ChoiceSetter);
|
||||
Trunk.registerSetter('CodeSetter', CodeSetter);
|
||||
Trunk.registerSetter('ColorSetter', ColorSetter);
|
||||
Trunk.registerSetter('DateSetter', DateSetter);
|
||||
Trunk.registerSetter('JsonSetter', JsonSetter);
|
||||
Trunk.registerSetter('ListSetter', ListSetter);
|
||||
Trunk.registerSetter('SelectSetter', SelectSetter);
|
||||
Trunk.registerSetter('OptionsSetter', OptionsSetter);
|
||||
Trunk.registerSetter('TextSetter', TextSetter);
|
||||
Trunk.registerSetter('NumberSetter', NumberSetter);
|
||||
Trunk.registerSetter('ValidationSetter', ValidationSetter);
|
||||
|
||||
// 需要额外覆盖配置的 setters
|
||||
|
||||
function wrapSetter(component: any, title: any, initialValueWrapper: any) {
|
||||
return {
|
||||
component,
|
||||
title,
|
||||
recommend: true,
|
||||
initialValue: initialValueWrapper ? (field: any) => {
|
||||
let defaultValueFromSetter;
|
||||
if (component.initial) {
|
||||
defaultValueFromSetter = component.initial.call(field, field.getValue());
|
||||
}
|
||||
const defaultValue = initialValueWrapper(defaultValueFromSetter);
|
||||
return defaultValue;
|
||||
} : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
Trunk.registerSetter('I18nSetter', wrapSetter(
|
||||
I18nSetter,
|
||||
{ type: 'i18n', 'zh-CN': '国际化输入', 'en-US': 'International Input' },
|
||||
(defaultValue: any) => {
|
||||
if (defaultValue[defaultValue.use] && typeof defaultValue[defaultValue.use] !== 'string') {
|
||||
defaultValue[defaultValue.use] = null;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
));
|
||||
|
||||
context.use(HOOKS.VE_SETTING_FIELD_VARIABLE_SETTER, VariableSetter);
|
||||
|
||||
const externals = ['react', 'react-dom', 'prop-types', 'react-router', 'react-router-dom', '@ali/recore'];
|
||||
|
||||
async function loadAssets() {
|
||||
const legaoAssets = await editor.utils.get('./legao-assets.json');
|
||||
|
||||
const assets = upgradeAssetsBundle(legaoAssets);
|
||||
|
||||
if (assets.packages) {
|
||||
assets.packages.forEach((item: any) => {
|
||||
if (item.package && externals.indexOf(item.package) > -1) {
|
||||
item.urls = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (assets['x-prototypes']) {
|
||||
const tasks: Array<Promise<any>> = [];
|
||||
const prototypeStyles: string[] = [];
|
||||
assets['x-prototypes'].forEach((pkg: any) => {
|
||||
if (pkg?.urls) {
|
||||
const urls = Array.isArray(pkg.urls) ? pkg.urls : [pkg.urls];
|
||||
urls.forEach((url: string) => {
|
||||
if (isCSSUrl(url)) {
|
||||
prototypeStyles.push(url);
|
||||
}
|
||||
});
|
||||
tasks.push(loadUrls(urls));
|
||||
}
|
||||
});
|
||||
if (prototypeStyles.length > 0) {
|
||||
assets.packages.push({
|
||||
library: '_prototypesStyle',
|
||||
package: '_prototypes-style',
|
||||
urls: prototypeStyles,
|
||||
});
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
// proccess snippets
|
||||
}
|
||||
|
||||
editor.set('legao-assets', legaoAssets);
|
||||
editor.set('assets', assets);
|
||||
}
|
||||
|
||||
async function loadSchema() {
|
||||
const schema = await editor.utils.get('./schema.json');
|
||||
editor.set('schema', schema);
|
||||
}
|
||||
|
||||
// demo
|
||||
function initDemoPanes() {
|
||||
skeleton.add({
|
||||
name: 'eventBindDialog',
|
||||
type: 'Widget',
|
||||
content: EventBindDialog,
|
||||
});
|
||||
|
||||
// skeleton.add({
|
||||
// area: 'left',
|
||||
// name: 'sourceEditor',
|
||||
// type: "PanelDock",
|
||||
// content: SourceEditor,
|
||||
// props: {
|
||||
// align: undefined,
|
||||
// description: "动作面板",
|
||||
// onDestroy: undefined,
|
||||
// icon: 'set',
|
||||
// onInit: undefined
|
||||
// },
|
||||
// panelProps:{
|
||||
// height: 300,
|
||||
// help: undefined,
|
||||
// hideTitleBar: true,
|
||||
// maxHeight: 800,
|
||||
// maxWidth: 1200,
|
||||
// title: "动作面板",
|
||||
// width: 600
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
// skeleton.add({
|
||||
// area: 'leftArea',
|
||||
// name: 'icon1',
|
||||
// type: 'PanelDock',
|
||||
// props: {
|
||||
// align: 'bottom',
|
||||
// icon: 'set',
|
||||
// description: '设置'
|
||||
// },
|
||||
// });
|
||||
|
||||
|
||||
skeleton.add({
|
||||
area: 'leftArea',
|
||||
name: 'icon2',
|
||||
type: 'Dock',
|
||||
props: {
|
||||
align: 'bottom',
|
||||
icon: 'help',
|
||||
description: '帮助'
|
||||
},
|
||||
});
|
||||
|
||||
skeleton.add({
|
||||
area: 'topArea',
|
||||
type: 'Dock',
|
||||
name: 'publish',
|
||||
props: {
|
||||
align: 'right',
|
||||
},
|
||||
content: createElement(Button, {
|
||||
size: 'small',
|
||||
type: 'secondary',
|
||||
children: '发布',
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
skeleton.add({
|
||||
area: 'topArea',
|
||||
type: 'Dock',
|
||||
name: 'save',
|
||||
props: {
|
||||
align: 'right',
|
||||
},
|
||||
content: createElement(Button, {
|
||||
size: 'small',
|
||||
type: 'primary',
|
||||
children: '保存',
|
||||
}),
|
||||
});
|
||||
// skeleton.add({
|
||||
// area: 'topArea',
|
||||
// type: 'Dock',
|
||||
// name: 'preview4',
|
||||
// props: {
|
||||
// align: 'center',
|
||||
// },
|
||||
// content: createElement('img', {
|
||||
// src: 'https://img.alicdn.com/tfs/TB1WW.VC.z1gK0jSZLeXXb9kVXa-486-64.png',
|
||||
// style: {
|
||||
// height: 32,
|
||||
// },
|
||||
// }),
|
||||
// });
|
||||
skeleton.add({
|
||||
area: 'topArea',
|
||||
type: 'Dock',
|
||||
name: 'preview1',
|
||||
props: {
|
||||
align: 'left',
|
||||
},
|
||||
content: createElement('img', {
|
||||
src: 'https://img.alicdn.com/tfs/TB1zqBfDlr0gK0jSZFnXXbRRXXa-440-64.png',
|
||||
style: {
|
||||
height: 32,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
async function initTrunkPane() {
|
||||
const assets = await editor.onceGot('legao-assets');
|
||||
const config = {
|
||||
disableLowCodeComponent: true,
|
||||
disableComponentStore: true,
|
||||
app: {
|
||||
getAssetsData() {
|
||||
return assets;
|
||||
// return data;
|
||||
},
|
||||
},
|
||||
};
|
||||
const TrunkPane = getTrunkPane(config);
|
||||
Panes.add(TrunkPane);
|
||||
}
|
||||
|
||||
// 数据源面板
|
||||
function initDataPoolPane() {
|
||||
const dpConfigs = {};
|
||||
|
||||
if (!dpConfigs) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetchContext.create('DataPoolPaneAPI', {
|
||||
saveGlobalConfig: {
|
||||
url: 'query/appConfig/saveGlobalConfig.json',
|
||||
method: 'POST',
|
||||
},
|
||||
saveOrUpdateAppDataPool: {
|
||||
url: 'query/appDataPool/saveOrUpdateAppDataPool.json',
|
||||
method: 'POST',
|
||||
},
|
||||
batchSaveOrUpdateAppDataPool: {
|
||||
url: 'query/appDataPool/batchSaveOrUpdateAppDataPool.json',
|
||||
method: 'POST'
|
||||
},
|
||||
listAppDataPool: {
|
||||
url: 'query/appDataPool/listAppDataPool.json',
|
||||
method: 'GET',
|
||||
},
|
||||
getAppDataPool: {
|
||||
url: 'query/appDataPool/getAppDataPool.json',
|
||||
method: 'POST',
|
||||
},
|
||||
getEpaasApiInApp: {
|
||||
url: 'query/formdesign/getEpaasApiInApp.jsonp',
|
||||
method: 'GET',
|
||||
},
|
||||
getFormListOrder: {
|
||||
url: 'query/formdesign/getFormListOrder.json',
|
||||
method: 'GET',
|
||||
},
|
||||
// 实时修改 effectForm
|
||||
operateAppDpBind: {
|
||||
url: 'query/appDataPool/operateAppDpBind.json',
|
||||
method: 'POST',
|
||||
},
|
||||
// 校验全局数据源是否被其他页面修改
|
||||
checkAppDataPoolModified: {
|
||||
url: 'query/appDataPool/checkAppDataPoolModified.json',
|
||||
method: 'POST',
|
||||
},
|
||||
});
|
||||
|
||||
const props = {
|
||||
enableGateService: true,
|
||||
enableGlobalFitConfig: true,
|
||||
enableOneAPIService: true,
|
||||
formUuid: 'xxx',
|
||||
api: fetchContext.api.DataPoolPaneAPI,
|
||||
};
|
||||
|
||||
Panes.add(DatapoolPane, {
|
||||
props,
|
||||
});
|
||||
}
|
||||
|
||||
// 国际化面板
|
||||
function initI18nPane() {
|
||||
fetchContext.create('I18nManagePaneAPI', {
|
||||
// 绑定美杜莎
|
||||
bindMedusa: {
|
||||
url: 'query/app/createMedusa.json',
|
||||
},
|
||||
|
||||
// 解除绑定
|
||||
unbindMedusa: {
|
||||
url: 'query/app/removeMedusa.json',
|
||||
},
|
||||
|
||||
// 同步美杜莎
|
||||
syncMedusa: {
|
||||
url: 'query/formi18n/syncI18n.json',
|
||||
},
|
||||
});
|
||||
|
||||
Panes.add(I18nManagePane, {
|
||||
props: {
|
||||
enableMedusa: true,
|
||||
api: fetchContext.api.I18nManagePaneAPI,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 动作面板
|
||||
function initActionPane() {
|
||||
actionUtil.setActions({
|
||||
module: {
|
||||
compiled: "'use strict';\n\nexports.__esModule = true;\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nexports.submit = submit;\nexports.onLoadData = onLoadData;\nexports.add = add;\nexports.edit = edit;\nexports.del = del;\nexports.search = search;\nexports.reset = reset;\n/**\n* 点击弹框的“确认”\n*/\nfunction submit() {\n var _this = this;\n\n this.$('form').submit(function (data, error) {\n if (data) {\n _this.dataSourceMap['table_submit'].load(data).then(function (res) {\n _this.utils.toast({\n type: 'success',\n title: '提交成功'\n });\n _this.$('dialog').hide();\n _this.dataSourceMap['table_list'].load();\n }).catch(function () {\n _this.utils.toast({\n type: 'error',\n title: '提交失败'\n });\n });\n }\n });\n}\n\n/**\n* tablePc onLoadData\n* @param currentPage 当前页码\n* @param pageSize 每页显示条数\n* @param searchKey 搜索关键字\n* @param orderColumn 排序列\n* @param orderType 排序方式(desc,asc)\n* @param from 触发来源(order,search,pagination)\n*/\nfunction onLoadData(currentPage, pageSize, searchKey, orderColumn, orderType, from) {\n var tableParams = {\n currentPage: from === 'search' ? 1 : currentPage,\n pageSize: pageSize,\n searchKey: searchKey,\n orderColumn: orderColumn,\n orderType: orderType\n };\n this.setState({ tableParams: tableParams });\n}\n\n// 点击新增\nfunction add() {\n this.setState({\n formData: null\n });\n this.$('dialog').show();\n}\n\n// 点击编辑\nfunction edit(rowData) {\n this.setState({\n formData: rowData\n });\n this.$('dialog').show();\n}\n\n// 点击删除\nfunction del(rowData) {\n var _this2 = this;\n\n this.utils.dialog({\n method: 'confirm',\n title: '提示',\n content: '确认删除该条目吗?',\n onOk: function onOk() {\n _this2.dataSourceMap['table_delete'].load({ id: rowData.id }).then(function () {\n _this2.utils.toast({\n type: 'success',\n title: '删除成功'\n });\n _this2.dataSourceMap['table_list'].load();\n }).catch(function () {\n _this2.utils.toast({\n type: 'error',\n title: '删除失败'\n });\n });\n }\n });\n}\n\n/**\n* button onClick\n*/\nfunction search() {\n var filterData = this.$('filter').getValue();\n this.setState({\n filterData: filterData,\n tableParams: _extends({}, this.state.tableParams, {\n time: Date.now(),\n currentPage: 1\n })\n });\n}\n\n/**\n* button onClick\n*/\nfunction reset() {\n this.$('filter').reset();\n this.setState({\n filterData: {},\n tableParams: _extends({}, this.state.tableParams, {\n time: Date.now(),\n currentPage: 1\n })\n });\n}",
|
||||
source: "/**\n* 点击弹框的“确认”\n*/\nexport function submit() {\n this.$('form').submit((data, error) => {\n if (data) {\n this.dataSourceMap['table_submit'].load(data).then((res) => {\n this.utils.toast({\n type: 'success',\n title: '提交成功'\n });\n this.$('dialog').hide();\n this.dataSourceMap['table_list'].load();\n }).catch(()=>{\n this.utils.toast({\n type: 'error',\n title: '提交失败'\n });\n })\n }\n })\n}\n\n/**\n* tablePc onLoadData\n* @param currentPage 当前页码\n* @param pageSize 每页显示条数\n* @param searchKey 搜索关键字\n* @param orderColumn 排序列\n* @param orderType 排序方式(desc,asc)\n* @param from 触发来源(order,search,pagination)\n*/\nexport function onLoadData(currentPage, pageSize, searchKey, orderColumn, orderType, from) {\n const tableParams = {\n currentPage: from === 'search' ? 1 : currentPage,\n pageSize,\n searchKey,\n orderColumn,\n orderType\n };\n this.setState({ tableParams });\n}\n\n// 点击新增\nexport function add() {\n this.setState({\n formData: null,\n });\n this.$('dialog').show();\n}\n\n\n// 点击编辑\nexport function edit(rowData) {\n this.setState({\n formData: rowData\n });\n this.$('dialog').show();\n}\n\n// 点击删除\nexport function del(rowData) {\n this.utils.dialog({\n method: 'confirm',\n title: '提示',\n content: '确认删除该条目吗?',\n onOk: () => {\n this.dataSourceMap['table_delete'].load({ id: rowData.id }).then(() => {\n this.utils.toast({\n type: 'success',\n title: '删除成功'\n });\n this.dataSourceMap['table_list'].load();\n }).catch(()=>{\n this.utils.toast({\n type: 'error',\n title: '删除失败'\n });\n })\n }\n })\n}\n\n/**\n* button onClick\n*/\nexport function search(){\n const filterData = this.$('filter').getValue();\n this.setState({\n filterData,\n tableParams: {\n ...this.state.tableParams,\n time: Date.now(),\n currentPage: 1\n }\n });\n}\n\n/**\n* button onClick\n*/\nexport function reset(){\n this.$('filter').reset();\n this.setState({\n filterData: {},\n tableParams: {\n ...this.state.tableParams,\n time: Date.now(),\n currentPage: 1\n }\n });\n}"
|
||||
},
|
||||
type: "FUNCTION",
|
||||
list: [
|
||||
{
|
||||
"id": "submit",
|
||||
"title": "submit"
|
||||
},
|
||||
{
|
||||
"id": "onLoadData",
|
||||
"title": "onLoadData"
|
||||
},
|
||||
{
|
||||
"id": "add",
|
||||
"title": "add"
|
||||
},
|
||||
{
|
||||
"id": "edit",
|
||||
"title": "edit"
|
||||
},
|
||||
{
|
||||
"id": "del",
|
||||
"title": "del"
|
||||
},
|
||||
{
|
||||
"id": "search",
|
||||
"title": "search"
|
||||
},
|
||||
{
|
||||
"id": "reset",
|
||||
"title": "reset"
|
||||
}
|
||||
]
|
||||
});
|
||||
const props = {
|
||||
enableGlobalJS: false,
|
||||
enableVsCodeEdit: false,
|
||||
enableHeaderTip: true,
|
||||
};
|
||||
|
||||
|
||||
Panes.add(ActionPane, {
|
||||
props,
|
||||
});
|
||||
}
|
||||
function replaceFuncProp(props?: any){
|
||||
const replaceProps: any = {};
|
||||
for (const name in props) {
|
||||
const prop = props[name];
|
||||
if (!prop) {
|
||||
continue;
|
||||
}
|
||||
if ((prop.compiled && prop.source) || prop.type === 'actionRef' || prop.type === 'js') {
|
||||
replaceProps[name] = funcParser(prop);
|
||||
} else if (_isObject(prop)) {
|
||||
replaceFuncProp(prop);
|
||||
} else if (_isArray(prop)) {
|
||||
prop.map((propItem) => {
|
||||
replaceFuncProp(propItem);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const name in replaceProps) {
|
||||
props[name] = replaceProps[name];
|
||||
}
|
||||
return props;
|
||||
};
|
||||
|
||||
// 操作历史与页面历史面板
|
||||
function initHistoryPane() {
|
||||
// let historyConfigs = {getDesignerModuleConfigs(
|
||||
// this.designerConfigs,
|
||||
// 'history',
|
||||
// )};
|
||||
let historyConfigs = {
|
||||
enableRedoAndUndo: true,
|
||||
enablePageHistory: true,
|
||||
};;
|
||||
|
||||
const isDemoMode = false;
|
||||
const isEnvSupportsHistoryPane = true;
|
||||
const historyManager = PageHistoryManager.getManager();
|
||||
|
||||
console.log('PageHistoryManager', historyManager);
|
||||
console.log('PageHistoryManager.onOpenPane', historyManager.onOpenPane);
|
||||
// 历史撤销、重做以及唤起页面历史按钮
|
||||
if (typeof HistoryPane === 'function') {
|
||||
Panes.add(HistoryPane, {
|
||||
props : {
|
||||
showPageHistory:
|
||||
isEnvSupportsHistoryPane
|
||||
// && this.app.isForm()
|
||||
&& !isDemoMode,
|
||||
historyManager,
|
||||
historyConfigs,
|
||||
index: -940,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Panes.add(HistoryPane, {
|
||||
index: -940,
|
||||
});
|
||||
}
|
||||
|
||||
// 页面历史 UI 面板
|
||||
if (
|
||||
PageHistoryPane
|
||||
&& !isDemoMode
|
||||
&& isEnvSupportsHistoryPane
|
||||
) {
|
||||
Panes.add(PageHistoryPane, {
|
||||
props : {
|
||||
historyManager: {
|
||||
historyManager,
|
||||
app: {
|
||||
|
||||
}
|
||||
},
|
||||
index: -940,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function init() {
|
||||
Engine.Env.setEnv('RE_VERSION', '7.2.0');
|
||||
Engine.Env.setSupportFeatures({
|
||||
subview: true,
|
||||
i18nPane: true,
|
||||
});
|
||||
Prototype.addGlobalPropsReducer(replaceFuncProp);
|
||||
await loadAssets();
|
||||
await loadSchema();
|
||||
await initTrunkPane();
|
||||
// initDataPoolPane();
|
||||
// initI18nPane();
|
||||
// initActionPane();
|
||||
initDemoPanes();
|
||||
// initHistoryPane();
|
||||
Engine.init();
|
||||
}
|
||||
init();
|
||||
172
packages/demo/src/vision/loader.js
Normal file
172
packages/demo/src/vision/loader.js
Normal file
@ -0,0 +1,172 @@
|
||||
/* eslint-disable */
|
||||
function getStylePoint(id, level) {
|
||||
if (stylePointTable[id]) {
|
||||
return stylePointTable[id];
|
||||
}
|
||||
|
||||
const base = getBasePoint();
|
||||
|
||||
if (id === 'base') {
|
||||
return base;
|
||||
}
|
||||
|
||||
const point = new StylePoint(id, level || 2000);
|
||||
if (level >= base.level) {
|
||||
let prev = base;
|
||||
let next = prev.next;
|
||||
while (next && level >= next.level) {
|
||||
prev = next;
|
||||
next = prev.next;
|
||||
}
|
||||
prev.next = point;
|
||||
point.prev = prev;
|
||||
if (next) {
|
||||
point.next = next;
|
||||
next.prev = point;
|
||||
}
|
||||
} else {
|
||||
let next = base;
|
||||
let prev = next.prev;
|
||||
while (prev && level < prev.level) {
|
||||
next = prev;
|
||||
prev = next.prev;
|
||||
}
|
||||
next.prev = point;
|
||||
point.next = next;
|
||||
if (prev) {
|
||||
point.prev = prev;
|
||||
prev.next = point;
|
||||
}
|
||||
}
|
||||
point.insert();
|
||||
stylePointTable[id] = point;
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
const stylePointTable = {};
|
||||
|
||||
function getBasePoint() {
|
||||
if (!stylePointTable.base) {
|
||||
stylePointTable.base = new StylePoint('base', 1000);
|
||||
stylePointTable.base.insert();
|
||||
}
|
||||
return stylePointTable.base;
|
||||
}
|
||||
|
||||
class StylePoint {
|
||||
constructor(id, level, placeholder) {
|
||||
this.lastContent = null;
|
||||
this.lastUrl = null;
|
||||
this.next = null;
|
||||
this.prev = null;
|
||||
this.id = id;
|
||||
this.level = level;
|
||||
if (placeholder) {
|
||||
this.placeholder = placeholder;
|
||||
} else {
|
||||
this.placeholder = document.createTextNode('');
|
||||
}
|
||||
}
|
||||
|
||||
insert() {
|
||||
if (this.next) {
|
||||
document.head.insertBefore(this.placeholder, this.next.placeholder);
|
||||
} else if (this.prev) {
|
||||
document.head.insertBefore(this.placeholder, this.prev.placeholder.nextSibling);
|
||||
} else {
|
||||
document.head.appendChild(this.placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
applyText(content) {
|
||||
if (this.lastContent === content) {
|
||||
return;
|
||||
}
|
||||
this.lastContent = content;
|
||||
this.lastUrl = undefined;
|
||||
const element = document.createElement('style');
|
||||
element.setAttribute('type', 'text/css');
|
||||
element.setAttribute('data-for', this.id);
|
||||
element.appendChild(document.createTextNode(content));
|
||||
document.head.insertBefore(element, this.placeholder);
|
||||
document.head.removeChild(this.placeholder);
|
||||
this.placeholder = element;
|
||||
}
|
||||
|
||||
applyUrl(url) {
|
||||
if (this.lastUrl === url) {
|
||||
return;
|
||||
}
|
||||
this.lastContent = undefined;
|
||||
this.lastUrl = url;
|
||||
const element = document.createElement('link');
|
||||
element.href = url;
|
||||
element.rel = 'stylesheet';
|
||||
element.setAttribute('data-for', this.id);
|
||||
document.head.insertBefore(element, this.placeholder);
|
||||
document.head.removeChild(this.placeholder);
|
||||
this.placeholder = element;
|
||||
}
|
||||
}
|
||||
|
||||
function loadCSS(url) {
|
||||
getStylePoint(url).applyUrl(url);
|
||||
}
|
||||
|
||||
function isCSSUrl(url) {
|
||||
return /\.css$/.test(url);
|
||||
}
|
||||
|
||||
function loadScript(url) {
|
||||
const node = document.createElement('script');
|
||||
|
||||
// node.setAttribute('crossorigin', 'anonymous');
|
||||
|
||||
node.onload = onload;
|
||||
node.onerror = onload;
|
||||
|
||||
const i = {};
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
i.resolve = resolve;
|
||||
i.reject = reject;
|
||||
});
|
||||
|
||||
function onload(e) {
|
||||
node.onload = null;
|
||||
node.onerror = null;
|
||||
if (e.type === 'load') {
|
||||
i.resolve();
|
||||
} else {
|
||||
i.reject();
|
||||
}
|
||||
// document.head.removeChild(node);
|
||||
// node = null;
|
||||
}
|
||||
|
||||
// node.async = true;
|
||||
node.src = url;
|
||||
|
||||
document.head.appendChild(node);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
export default function loadUrls(urls) {
|
||||
if (!urls || urls.length < 1) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let promise = null;
|
||||
urls.forEach((url) => {
|
||||
if (isCSSUrl(url)) {
|
||||
loadCSS(url);
|
||||
} else if (!promise) {
|
||||
promise = loadScript(url);
|
||||
} else {
|
||||
promise = promise.then(() => loadScript(url));
|
||||
}
|
||||
});
|
||||
|
||||
return promise || Promise.resolve();
|
||||
}
|
||||
13
packages/demo/src/vision/module.d.ts
vendored
Normal file
13
packages/demo/src/vision/module.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
declare module '@ali/visualengine';
|
||||
declare module '@ali/visualengine-utils';
|
||||
declare module '@ali/ve-trunk-pane';
|
||||
declare module '@ali/vs-variable-setter';
|
||||
declare module '@ali/ve-datapool-pane';
|
||||
declare module '@ali/ve-history-pane';
|
||||
declare module '@ali/ve-page-history-pane';
|
||||
declare module '@ali/ve-page-history';
|
||||
declare module '@ali/ve-i18n-manage-pane';
|
||||
declare module '@ali/ve-action-pane';
|
||||
declare module '@ali/vu-legao-design-fetch-context';
|
||||
declare module "@ali/vu-function-parser";
|
||||
declare module "compare-versions";
|
||||
68
packages/demo/src/vision/upgrade-assets.js
Normal file
68
packages/demo/src/vision/upgrade-assets.js
Normal file
@ -0,0 +1,68 @@
|
||||
/* eslint-disable */
|
||||
export function upgradeAssetsBundle(assets) {
|
||||
const components = [];
|
||||
const xPrototypes = [];
|
||||
const componentList = [];
|
||||
const packages = assets.externals.map(({ urls, library, name, version }) => {
|
||||
return {
|
||||
package: name,
|
||||
version,
|
||||
urls,
|
||||
library,
|
||||
};
|
||||
});
|
||||
assets.componentDependencies.forEach((item) => {
|
||||
const componentName = item.alias || item.library;
|
||||
const metadata = {
|
||||
componentName,
|
||||
npm: {
|
||||
package: item.packageName,
|
||||
library: item.library,
|
||||
version: item.version,
|
||||
destructuring: false,
|
||||
},
|
||||
props: [],
|
||||
};
|
||||
|
||||
if (item.prototypeConfigsUrl) {
|
||||
xPrototypes.push({
|
||||
package: item.packageName,
|
||||
urls: item.prototypeConfigsUrl,
|
||||
});
|
||||
} else if (item.components) {
|
||||
packages.push({
|
||||
urls: item.urls,
|
||||
library: item.library,
|
||||
package: item.packageName,
|
||||
version: item.version,
|
||||
});
|
||||
const meta = item.components[0];
|
||||
metadata.componentName = meta.componentName;
|
||||
metadata.configure = meta.configure;
|
||||
metadata.title = meta.title;
|
||||
components.push(metadata);
|
||||
// TODO:
|
||||
if (meta.snippets) {
|
||||
componentList.push({
|
||||
title: meta.category,
|
||||
icon: '',
|
||||
children: [
|
||||
{
|
||||
title: 'json格式化展示',
|
||||
icon: '',
|
||||
snippets: meta.snippets,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
"version": "1.0.0",
|
||||
packages,
|
||||
'x-prototypes': xPrototypes,
|
||||
components,
|
||||
componentList
|
||||
};
|
||||
}
|
||||
@ -3,6 +3,264 @@
|
||||
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.23"></a>
|
||||
## [0.9.23](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.21...@ali/lowcode-designer@0.9.23) (2020-06-23)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.21"></a>
|
||||
## [0.9.21](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.20...@ali/lowcode-designer@0.9.21) (2020-06-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 1. 修复dialog拖入不显示问题 2. dialog 只能在根节点下 3. 引入 modalNodeManager ([65977e7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/65977e7))
|
||||
* add extraEnv ([9058ac8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9058ac8))
|
||||
* 修复低代码组件设计器、区块设计器根节点为 Page 的问题,修复 topArea 样式 ([e85b542](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e85b542))
|
||||
* 支持事件 VE_EVENTS.VE_PAGE_PAGE_READY ([935ffad](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/935ffad))
|
||||
* 支持页面回滚 ([5d7dc2f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5d7dc2f))
|
||||
* 更改生成 id 的规则, 否则命中 recore 解析 id 的一个限制 ([5adff44](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/5adff44))
|
||||
* 根据目标元素的canDropIn函数判断是否能放入其他元素 ([21d4f64](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/21d4f64))
|
||||
* 简化 onPageReady 实现逻辑 ([a36e5f2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a36e5f2))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 增加 node replaceWith 方法 ([d44f95b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d44f95b))
|
||||
* 引擎层埋点 ([69de533](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/69de533))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.20"></a>
|
||||
## [0.9.20](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.19...@ali/lowcode-designer@0.9.20) (2020-06-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.19"></a>
|
||||
## [0.9.19](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.18...@ali/lowcode-designer@0.9.19) (2020-06-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* force schema ([6d0a8ff](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6d0a8ff))
|
||||
* patch prototype ([f20bfaa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f20bfaa))
|
||||
* try get settingfield ([56f242f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56f242f))
|
||||
* 禁止组件拉到 Page 的直接子节点, 以及替换 tab 组件 ([d93a291](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/d93a291))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* complete live-editing expr & i18n ([3ac08ba](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/3ac08ba))
|
||||
* get SettingField instead of SettingPropEntry for compatibility ([2787a12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2787a12))
|
||||
* support prop.autorun ([c0a5235](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c0a5235))
|
||||
* ve事件埋点 ([700e5b0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/700e5b0))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.18"></a>
|
||||
## [0.9.18](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.17...@ali/lowcode-designer@0.9.18) (2020-05-20)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.17"></a>
|
||||
## [0.9.17](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.16...@ali/lowcode-designer@0.9.17) (2020-05-19)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.16"></a>
|
||||
## [0.9.16](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.15...@ali/lowcode-designer@0.9.16) (2020-05-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* uniqueid ([8db52f0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/8db52f0))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.15"></a>
|
||||
## [0.9.15](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.14...@ali/lowcode-designer@0.9.15) (2020-05-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.14"></a>
|
||||
## [0.9.14](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.13...@ali/lowcode-designer@0.9.14) (2020-05-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.13"></a>
|
||||
## [0.9.13](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.12...@ali/lowcode-designer@0.9.13) (2020-05-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.12"></a>
|
||||
## [0.9.12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.11...@ali/lowcode-designer@0.9.12) (2020-05-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* change reducer stage ([c2e83c7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c2e83c7))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.11"></a>
|
||||
## [0.9.11](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.10...@ali/lowcode-designer@0.9.11) (2020-05-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ? to component designer/src/designer/setting/utils.js ([0025e3c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0025e3c))
|
||||
* add alias for get index ([e853a4f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/e853a4f))
|
||||
* add resize box ([14a55ae](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/14a55ae))
|
||||
* bord resizing ([361f4f6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/361f4f6))
|
||||
* border resizing ([c7fc28c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/c7fc28c))
|
||||
* for box resizing ([77e325f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/77e325f))
|
||||
* for box resizing ([cb2854d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/cb2854d))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.10"></a>
|
||||
## [0.9.10](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.9...@ali/lowcode-designer@0.9.10) (2020-05-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* handling the undefined variable ([0efe8b4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0efe8b4))
|
||||
* lc-borders-actions ([56d9f5f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/56d9f5f))
|
||||
* 修复 toolbar 弹出位置异常 ([b40b9a4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/b40b9a4))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.9"></a>
|
||||
## [0.9.9](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.8...@ali/lowcode-designer@0.9.9) (2020-05-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 add hotkey up/down/left/right ([9c8afe8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/9c8afe8))
|
||||
* 🐛 error when quick search ([801d954](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/801d954))
|
||||
* 🐛 快捷键支持 ([73374dd](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/73374dd))
|
||||
* 🐛 移动快捷键 ([7c8a27c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7c8a27c))
|
||||
* cancel dragging on invalid position ([f961096](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f961096))
|
||||
* panel visible time ([18ac1fa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/18ac1fa))
|
||||
* quickSearch error ([a8009ef](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a8009ef))
|
||||
* supports ([371b84c](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/371b84c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* show value state ([bd49e50](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/bd49e50))
|
||||
* support global inline editing ([4f7179b](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/4f7179b))
|
||||
* support plaintext liveediting ([ea62f12](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ea62f12))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.8"></a>
|
||||
## [0.9.8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.7...@ali/lowcode-designer@0.9.8) (2020-05-08)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.7"></a>
|
||||
## [0.9.7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.6...@ali/lowcode-designer@0.9.7) (2020-05-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 🐛 add pollyfill for vision page.getHistory ([0b905d0](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/0b905d0))
|
||||
* 🐛 title缺少icon字段,临时转接一下 ([2f9bb25](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2f9bb25))
|
||||
* 🐛 增加 getAddonData api ([68b7e29](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/68b7e29))
|
||||
* 🐛 增加剪切快捷键 ([a73a82e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/a73a82e))
|
||||
* border action style ([6b91535](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/6b91535))
|
||||
* documentModel toData 方法 ([1ea0d73](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/1ea0d73))
|
||||
* settingfield添加props修复地区组件切换类型报错 ([88348f7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/88348f7))
|
||||
* 在Transducer中添加对MixedSetter的支持 ([7317f2f](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7317f2f))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 增加icon获取api ([f1a0823](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/f1a0823))
|
||||
* duplicate ([ec932aa](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ec932aa))
|
||||
* 修复状态切换失效 ([2e3f60d](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/2e3f60d))
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="0.9.6"></a>
|
||||
## [0.9.6](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.5...@ali/lowcode-designer@0.9.6) (2020-04-27)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.5"></a>
|
||||
## [0.9.5](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.4...@ali/lowcode-designer@0.9.5) (2020-04-27)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.4"></a>
|
||||
## [0.9.4](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.3...@ali/lowcode-designer@0.9.4) (2020-04-27)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.3"></a>
|
||||
## [0.9.3](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.2...@ali/lowcode-designer@0.9.3) (2020-04-16)
|
||||
|
||||
|
||||
|
||||
|
||||
**Note:** Version bump only for package @ali/lowcode-designer
|
||||
|
||||
<a name="0.9.2"></a>
|
||||
## [0.9.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-designer@0.9.1...@ali/lowcode-designer@0.9.2) (2020-04-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 polyfill exchange ([7070557](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/7070557))
|
||||
* 🎸 polyfill exchange ([286e7d8](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/286e7d8))
|
||||
* Exchange ([ef5a72e](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/ef5a72e))
|
||||
* run vision polyfill ([33750b7](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/commit/33750b7))
|
||||
|
||||
|
||||
|
||||
|
||||
<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)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ali/lowcode-designer",
|
||||
"version": "0.9.1",
|
||||
"version": "0.9.23",
|
||||
"description": "Designer for Ali LowCode Engine",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
@ -15,8 +15,11 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ali/lowcode-globals": "^0.9.1",
|
||||
"@ali/lowcode-editor-core": "^0.8.19",
|
||||
"@ali/lowcode-types": "^0.8.9",
|
||||
"@ali/lowcode-utils": "^0.8.10",
|
||||
"classnames": "^2.2.6",
|
||||
"event": "^1.0.0",
|
||||
"react": "^16",
|
||||
"react-dom": "^16.7.0"
|
||||
},
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Component, Fragment, PureComponent } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { computed, observer, TitleContent, Title } from '@ali/lowcode-globals';
|
||||
import { SimulatorContext } from '../context';
|
||||
import { computed, observer, Title } from '@ali/lowcode-editor-core';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
import { TitleContent } from '@ali/lowcode-types';
|
||||
|
||||
export class BorderHoveringInstance extends PureComponent<{
|
||||
export class BorderDetectingInstance extends PureComponent<{
|
||||
title: TitleContent;
|
||||
rect: DOMRect | null;
|
||||
scale: number;
|
||||
@ -23,7 +23,7 @@ export class BorderHoveringInstance extends PureComponent<{
|
||||
transform: `translate(${(scrollX + rect.left) * scale}px, ${(scrollY + rect.top) * scale}px)`,
|
||||
};
|
||||
|
||||
const className = classNames('lc-borders lc-borders-hovering');
|
||||
const className = classNames('lc-borders lc-borders-detecting');
|
||||
|
||||
// TODO:
|
||||
// 1. thinkof icon
|
||||
@ -38,30 +38,28 @@ export class BorderHoveringInstance extends PureComponent<{
|
||||
}
|
||||
|
||||
@observer
|
||||
export class BorderHovering extends Component {
|
||||
static contextType = SimulatorContext;
|
||||
|
||||
export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@computed get scale() {
|
||||
return (this.context as BuiltinSimulatorHost).viewport.scale;
|
||||
return this.props.host.viewport.scale;
|
||||
}
|
||||
|
||||
@computed get scrollX() {
|
||||
return (this.context as BuiltinSimulatorHost).viewport.scrollX;
|
||||
return this.props.host.viewport.scrollX;
|
||||
}
|
||||
|
||||
@computed get scrollY() {
|
||||
return (this.context as BuiltinSimulatorHost).viewport.scrollY;
|
||||
return this.props.host.viewport.scrollY;
|
||||
}
|
||||
|
||||
@computed get current() {
|
||||
const host = this.context as BuiltinSimulatorHost;
|
||||
const host = this.props.host;
|
||||
const doc = host.document;
|
||||
const selection = doc.selection;
|
||||
const current = host.designer.hovering.current;
|
||||
const current = host.designer.detecting.current;
|
||||
if (!current || current.document !== doc || selection.has(current.id)) {
|
||||
return null;
|
||||
}
|
||||
@ -69,38 +67,38 @@ export class BorderHovering extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const host = this.context as BuiltinSimulatorHost;
|
||||
const host = this.props.host;
|
||||
const current = this.current;
|
||||
if (!current || host.viewport.scrolling) {
|
||||
return <Fragment />;
|
||||
if (!current || host.viewport.scrolling || host.liveEditing.editing) {
|
||||
return null;
|
||||
}
|
||||
const instances = host.getComponentInstances(current);
|
||||
if (!instances || instances.length < 1) {
|
||||
return <Fragment />;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (instances.length === 1) {
|
||||
return (
|
||||
<BorderHoveringInstance
|
||||
<BorderDetectingInstance
|
||||
key="line-h"
|
||||
title={current.title}
|
||||
scale={this.scale}
|
||||
scrollX={this.scrollX}
|
||||
scrollY={this.scrollY}
|
||||
rect={host.computeComponentInstanceRect(instances[0], current.componentMeta.rectSelector)}
|
||||
rect={host.computeComponentInstanceRect(instances[0], current.componentMeta.rootSelector)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
{instances.map((inst, i) => (
|
||||
<BorderHoveringInstance
|
||||
<BorderDetectingInstance
|
||||
key={`line-h-${i}`}
|
||||
title={current.title}
|
||||
scale={this.scale}
|
||||
scrollX={this.scrollX}
|
||||
scrollY={this.scrollY}
|
||||
rect={host.computeComponentInstanceRect(inst, current.componentMeta.rectSelector)}
|
||||
rect={host.computeComponentInstanceRect(inst, current.componentMeta.rootSelector)}
|
||||
/>
|
||||
))}
|
||||
</Fragment>
|
||||
@ -0,0 +1,284 @@
|
||||
import { Component, Fragment } from 'react';
|
||||
import DragResizeEngine from './drag-resize-engine';
|
||||
import { observer, computed, globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||
import classNames from 'classnames';
|
||||
import { SimulatorContext } from '../context';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
import { OffsetObserver, Designer } from '../../designer';
|
||||
|
||||
@observer
|
||||
export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
static contextType = SimulatorContext;
|
||||
|
||||
get host(): BuiltinSimulatorHost {
|
||||
return this.props.host;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
// this.hoveringCapture.setBoundary(this.outline);
|
||||
// this.willBind();
|
||||
}
|
||||
|
||||
render() {
|
||||
const selecting = this.selecting;
|
||||
if (!selecting || selecting.length < 1) {
|
||||
// DIRTY FIX, recore has a bug!
|
||||
return <Fragment />;
|
||||
}
|
||||
|
||||
// const componentMeta = selecting[0].componentMeta;
|
||||
// const metaData = componentMeta.getMetadata();
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{selecting.map((node) => (
|
||||
<BoxResizingForNode key={node.id} node={node} host={this.props.host} />
|
||||
))}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {
|
||||
static contextType = SimulatorContext;
|
||||
|
||||
get host(): BuiltinSimulatorHost {
|
||||
return this.props.host;
|
||||
}
|
||||
|
||||
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: any) => {
|
||||
const observed = designer.createOffsetObserver({
|
||||
node,
|
||||
instance,
|
||||
});
|
||||
if (!observed) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<BoxResizingInstance key={observed.id} dragging={this.dragging} designer={designer} observed={observed} />
|
||||
);
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
export class BoxResizingInstance extends Component<{
|
||||
observed: OffsetObserver;
|
||||
highlight?: boolean;
|
||||
dragging?: boolean;
|
||||
designer?: Designer;
|
||||
}> {
|
||||
// private outline: any;
|
||||
private willUnbind: () => any;
|
||||
private outlineRight: any;
|
||||
private outlineLeft: any;
|
||||
private dragEngine: DragResizeEngine;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.dragEngine = new DragResizeEngine(props.designer);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.willUnbind) {
|
||||
this.willUnbind();
|
||||
}
|
||||
this.props.observed.purge();
|
||||
}
|
||||
|
||||
getExperiMentalFns = (metaData: any) => {
|
||||
if (metaData.experimental && metaData.experimental.callbacks) {
|
||||
return metaData.experimantal.callbacks;
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
// this.hoveringCapture.setBoundary(this.outline);
|
||||
this.willBind();
|
||||
|
||||
const resize = (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => {
|
||||
const metaData = node.componentMeta.getMetadata();
|
||||
if (
|
||||
metaData &&
|
||||
metaData.experimental &&
|
||||
metaData.experimental.callbacks &&
|
||||
typeof metaData.experimental.callbacks.onResize === 'function'
|
||||
) {
|
||||
e.trigger = direction;
|
||||
e.deltaX = moveX;
|
||||
e.deltaY = moveY;
|
||||
metaData.experimental.callbacks.onResize(e, node);
|
||||
}
|
||||
};
|
||||
|
||||
const resizeStart = (e: MouseEvent, direction: string, node: any) => {
|
||||
const metaData = node.componentMeta.getMetadata();
|
||||
if (
|
||||
metaData &&
|
||||
metaData.experimental &&
|
||||
metaData.experimental.callbacks &&
|
||||
typeof metaData.experimental.callbacks.onResizeStart === 'function'
|
||||
) {
|
||||
e.trigger = direction;
|
||||
metaData.experimental.callbacks.onResizeStart(e, node);
|
||||
}
|
||||
};
|
||||
|
||||
const resizeEnd = (e: MouseEvent, direction: string, node: any) => {
|
||||
const metaData = node.componentMeta.getMetadata();
|
||||
if (
|
||||
metaData &&
|
||||
metaData.experimental &&
|
||||
metaData.experimental.callbacks &&
|
||||
typeof metaData.experimental.callbacks.onResizeEnd === 'function'
|
||||
) {
|
||||
e.trigger = direction;
|
||||
metaData.experimental.callbacks.onResizeStart(e, node);
|
||||
}
|
||||
|
||||
const editor = globalContext.get(Editor);
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.border.resize', {
|
||||
selected,
|
||||
layout: node?.parent?.getPropValue('layout') || '',
|
||||
});
|
||||
};
|
||||
|
||||
this.dragEngine.onResize(resize);
|
||||
this.dragEngine.onResizeStart(resizeStart);
|
||||
this.dragEngine.onResizeEnd(resizeEnd);
|
||||
}
|
||||
|
||||
willBind() {
|
||||
if (this.willUnbind) {
|
||||
this.willUnbind();
|
||||
}
|
||||
|
||||
if (!this.outlineRight && !this.outlineLeft) {
|
||||
return;
|
||||
}
|
||||
|
||||
const unBind: any[] = [];
|
||||
|
||||
unBind.push(
|
||||
this.dragEngine.from(this.outlineRight, 'e', () => {
|
||||
// if (!this.hoveringLine.hasOutline()) {
|
||||
// return null;
|
||||
// }
|
||||
// return this.hoveringLine.getCurrentNode();
|
||||
return this.props.observed.node;
|
||||
}),
|
||||
);
|
||||
unBind.push(
|
||||
this.dragEngine.from(this.outlineLeft, 'w', () => {
|
||||
return this.props.observed.node;
|
||||
// if (!this.hoveringLine.hasOutline()) {
|
||||
// return null;
|
||||
// }
|
||||
// return this.hoveringLine.getCurrentNode();
|
||||
}),
|
||||
);
|
||||
|
||||
this.willUnbind = () => {
|
||||
if (unBind && unBind.length > 0) {
|
||||
unBind.forEach((item) => {
|
||||
item();
|
||||
});
|
||||
}
|
||||
this.willUnbind = () => {};
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { observed } = this.props;
|
||||
if (!observed.hasOffset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { node, offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed;
|
||||
let triggerVisible: any = [];
|
||||
const metaData = node.componentMeta.getMetadata();
|
||||
if (metaData && metaData.experimental && metaData.experimental.getResizingHandlers) {
|
||||
triggerVisible = metaData.experimental.getResizingHandlers(node);
|
||||
}
|
||||
|
||||
const className = classNames('lc-borders lc-resize-box');
|
||||
|
||||
return (
|
||||
<div>
|
||||
{triggerVisible.includes('w') && (
|
||||
<div
|
||||
ref={(ref) => {
|
||||
this.outlineLeft = ref;
|
||||
}}
|
||||
className={className}
|
||||
style={{
|
||||
height: offsetHeight,
|
||||
transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`,
|
||||
width: 20,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{triggerVisible.includes('e') && (
|
||||
<div
|
||||
className={className}
|
||||
ref={(ref) => {
|
||||
this.outlineRight = ref;
|
||||
}}
|
||||
style={{
|
||||
height: offsetHeight,
|
||||
transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`,
|
||||
width: 20,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -9,19 +9,13 @@ import {
|
||||
ComponentType,
|
||||
} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
observer,
|
||||
computed,
|
||||
createIcon,
|
||||
EmbedTip,
|
||||
isReactComponent,
|
||||
ActionContentObject,
|
||||
isActionContentObject,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { SimulatorContext } from '../context';
|
||||
import { observer, computed, Tip, globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||
import { createIcon, isReactComponent } from '@ali/lowcode-utils';
|
||||
import { ActionContentObject, isActionContentObject } from '@ali/lowcode-types';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
import { OffsetObserver } from '../../../designer';
|
||||
import { Node } from '../../../document';
|
||||
import { OffsetObserver } from '../../designer';
|
||||
import { Node } from '../../document';
|
||||
import NodeSelector from '../node-selector';
|
||||
|
||||
@observer
|
||||
export class BorderSelectingInstance extends Component<{
|
||||
@ -75,7 +69,6 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
|
||||
let style: any;
|
||||
if (observed.top > SPACE_HEIGHT) {
|
||||
style = {
|
||||
right: Math.max(-BORDER, observed.right - width - BORDER),
|
||||
top: -SPACE_HEIGHT,
|
||||
height: BAR_HEIGHT,
|
||||
};
|
||||
@ -83,30 +76,34 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
|
||||
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),
|
||||
};
|
||||
}
|
||||
if (observed.width < 140) {
|
||||
style.left = Math.max(-BORDER, observed.left - width - BORDER);
|
||||
} else {
|
||||
style.right = Math.max(-BORDER, observed.right - width - BORDER);
|
||||
}
|
||||
const { node } = observed;
|
||||
const actions: ReactNodeArray = [];
|
||||
node.componentMeta.availableActions.forEach(action => {
|
||||
node.componentMeta.availableActions.forEach((action) => {
|
||||
const { important, condition, content, name } = action;
|
||||
if (node.isSlotRoot && (name === 'copy' || name === 'remove')) {
|
||||
if (node.isSlot() && (name === 'copy' || name === 'remove')) {
|
||||
// FIXME: need this?
|
||||
return;
|
||||
}
|
||||
if (important && (typeof condition === 'function' ? condition(node) : condition !== false)) {
|
||||
if (important && (typeof condition === 'function' ? condition(node) !== false : condition !== false)) {
|
||||
actions.push(createAction(content, name, node));
|
||||
}
|
||||
});
|
||||
return (
|
||||
<div className="lc-borders-actions" style={style}>
|
||||
{actions}
|
||||
<NodeSelector node={node} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -120,17 +117,27 @@ function createAction(content: ReactNode | ComponentType<any> | ActionContentObj
|
||||
return createElement(content, { key, node });
|
||||
}
|
||||
if (isActionContentObject(content)) {
|
||||
const { action, description, icon } = content;
|
||||
const { action, title, icon } = content;
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="lc-borders-action"
|
||||
onClick={() => {
|
||||
action && action(node);
|
||||
const editor = globalContext.get(Editor);
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const target =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.border.action', {
|
||||
name: key,
|
||||
target,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{icon && createIcon(icon)}
|
||||
<EmbedTip>{description}</EmbedTip>
|
||||
<Tip>{title}</Tip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -138,11 +145,9 @@ function createAction(content: ReactNode | ComponentType<any> | ActionContentObj
|
||||
}
|
||||
|
||||
@observer
|
||||
export class BorderSelectingForNode extends Component<{ node: Node }> {
|
||||
static contextType = SimulatorContext;
|
||||
|
||||
export class BorderSelectingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> {
|
||||
get host(): BuiltinSimulatorHost {
|
||||
return this.context;
|
||||
return this.props.host;
|
||||
}
|
||||
|
||||
get dragging(): boolean {
|
||||
@ -167,7 +172,7 @@ export class BorderSelectingForNode extends Component<{ node: Node }> {
|
||||
}
|
||||
return (
|
||||
<Fragment key={node.id}>
|
||||
{instances.map(instance => {
|
||||
{instances.map((instance) => {
|
||||
const observed = designer.createOffsetObserver({
|
||||
node,
|
||||
instance,
|
||||
@ -183,11 +188,9 @@ export class BorderSelectingForNode extends Component<{ node: Node }> {
|
||||
}
|
||||
|
||||
@observer
|
||||
export class BorderSelecting extends Component {
|
||||
static contextType = SimulatorContext;
|
||||
|
||||
export class BorderSelecting extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
get host(): BuiltinSimulatorHost {
|
||||
return this.context;
|
||||
return this.props.host;
|
||||
}
|
||||
|
||||
get dragging(): boolean {
|
||||
@ -196,7 +199,7 @@ export class BorderSelecting extends Component {
|
||||
|
||||
@computed get selecting() {
|
||||
const doc = this.host.document;
|
||||
if (doc.suspensed) {
|
||||
if (doc.suspensed || this.host.liveEditing.editing) {
|
||||
return null;
|
||||
}
|
||||
const selection = doc.selection;
|
||||
@ -210,14 +213,13 @@ export class BorderSelecting extends Component {
|
||||
render() {
|
||||
const selecting = this.selecting;
|
||||
if (!selecting || selecting.length < 1) {
|
||||
// DIRTY FIX, recore has a bug!
|
||||
return <Fragment />;
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{selecting.map(node => (
|
||||
<BorderSelectingForNode key={node.id} node={node} />
|
||||
{selecting.map((node) => (
|
||||
<BorderSelectingForNode key={node.id} host={this.props.host} node={node} />
|
||||
))}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
@ -25,9 +25,13 @@
|
||||
align-items: stretch;
|
||||
justify-content: flex-end;
|
||||
pointer-events: all;
|
||||
> * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-action {
|
||||
&-action,
|
||||
.ve-icon-button.ve-action-save {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
height: 20px;
|
||||
@ -45,7 +49,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
&&-hovering {
|
||||
&.lc-resize-box {
|
||||
border-width: 0;
|
||||
z-index: 1;
|
||||
cursor: ew-resize;
|
||||
pointer-events: auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
height: calc(100% - 20px);
|
||||
min-height: 50%;
|
||||
width: 4px;
|
||||
background: #738397;
|
||||
border-radius: 2px;
|
||||
// animation: flashing 1.5s infinite linear;
|
||||
}
|
||||
}
|
||||
|
||||
// &&-hovering {
|
||||
&&-detecting {
|
||||
z-index: 1;
|
||||
border-style: dashed;
|
||||
background: rgba(0,121,242,.04);
|
||||
|
||||
@ -0,0 +1,154 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { ISimulatorHost, isSimulatorHost } from '../../simulator';
|
||||
import { Designer, Point } from '../../designer';
|
||||
import { setNativeSelection, cursor } from '@ali/lowcode-utils';
|
||||
// import Cursor from './cursor';
|
||||
// import Pages from './pages';
|
||||
|
||||
function makeEventsHandler(
|
||||
boostEvent: MouseEvent | DragEvent,
|
||||
sensors: ISimulatorHost[],
|
||||
): (fn: (sdoc: Document) => void) => void {
|
||||
const topDoc = window.top.document;
|
||||
const sourceDoc = boostEvent.view?.document || topDoc;
|
||||
// TODO: optimize this logic, reduce listener
|
||||
// const boostPrevented = boostEvent.defaultPrevented;
|
||||
const docs = new Set<Document>();
|
||||
// if (boostPrevented || isDragEvent(boostEvent)) {
|
||||
docs.add(topDoc);
|
||||
// }
|
||||
docs.add(sourceDoc);
|
||||
// if (sourceDoc !== topDoc || isDragEvent(boostEvent)) {
|
||||
sensors.forEach((sim) => {
|
||||
const sdoc = sim.contentDocument;
|
||||
if (sdoc) {
|
||||
docs.add(sdoc);
|
||||
}
|
||||
});
|
||||
// }
|
||||
|
||||
return (handle: (sdoc: Document) => void) => {
|
||||
docs.forEach((doc) => handle(doc));
|
||||
};
|
||||
}
|
||||
|
||||
// 拖动缩放
|
||||
export default class DragResizeEngine {
|
||||
private emitter: EventEmitter;
|
||||
private dragResizing = false;
|
||||
|
||||
constructor(readonly designer: Designer) {
|
||||
this.designer = designer;
|
||||
this.emitter = new EventEmitter();
|
||||
}
|
||||
|
||||
private getMasterSensors(): ISimulatorHost[] {
|
||||
return this.designer.project.documents
|
||||
.map((doc) => {
|
||||
// TODO: not use actived,
|
||||
if (doc.actived && doc.simulator?.sensorAvailable) {
|
||||
return doc.simulator;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(Boolean) as any;
|
||||
}
|
||||
|
||||
isDragResizing() {
|
||||
return this.dragResizing;
|
||||
}
|
||||
|
||||
/**
|
||||
* drag reszie from
|
||||
* @param shell
|
||||
* @param direction n/s/e/w
|
||||
* @param boost (e: MouseEvent) => VE.Node
|
||||
*/
|
||||
from(shell: Element, direction: string, boost: (e: MouseEvent) => any) {
|
||||
let node: any;
|
||||
let startEvent: Point;
|
||||
|
||||
if (!shell) {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const move = (e: MouseEvent) => {
|
||||
const x = createResizeEvent(e);
|
||||
const moveX = x.clientX - startEvent.clientX;
|
||||
const moveY = x.clientY - startEvent.clientY;
|
||||
|
||||
this.emitter.emit('resize', e, direction, node, moveX, moveY);
|
||||
};
|
||||
|
||||
const masterSensors = this.getMasterSensors();
|
||||
|
||||
const createResizeEvent = (e: MouseEvent | DragEvent): Point => {
|
||||
const evt: any = {};
|
||||
|
||||
const sourceDocument = e.view?.document;
|
||||
|
||||
if (!sourceDocument || sourceDocument === document) {
|
||||
return e;
|
||||
}
|
||||
const srcSim = masterSensors.find((sim) => sim.contentDocument === sourceDocument);
|
||||
if (srcSim) {
|
||||
return srcSim.viewport.toGlobalPoint(e);
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
const over = (e: MouseEvent) => {
|
||||
const handleEvents = makeEventsHandler(e, masterSensors);
|
||||
handleEvents((doc) => {
|
||||
doc.removeEventListener('mousemove', move, true);
|
||||
doc.removeEventListener('mouseup', over, true);
|
||||
});
|
||||
|
||||
this.dragResizing = false;
|
||||
cursor.release();
|
||||
|
||||
this.emitter.emit('resizeEnd', e, direction, node);
|
||||
};
|
||||
|
||||
const mousedown = (e: MouseEvent) => {
|
||||
node = boost(e);
|
||||
startEvent = createResizeEvent(e);
|
||||
const handleEvents = makeEventsHandler(e, masterSensors);
|
||||
handleEvents((doc) => {
|
||||
doc.addEventListener('mousemove', move, true);
|
||||
doc.addEventListener('mouseup', over, true);
|
||||
});
|
||||
|
||||
this.emitter.emit('resizestart', e, direction, node);
|
||||
this.dragResizing = true;
|
||||
cursor.addState('ew-resize');
|
||||
};
|
||||
shell.addEventListener('mousedown', mousedown);
|
||||
return () => {
|
||||
shell.removeEventListener('mousedown', mousedown);
|
||||
};
|
||||
}
|
||||
|
||||
onResizeStart(func: (e: MouseEvent, direction: string, node: any) => any) {
|
||||
this.emitter.on('resizestart', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('resizestart', func);
|
||||
};
|
||||
}
|
||||
|
||||
onResize(func: (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => any) {
|
||||
this.emitter.on('resize', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('resize', func);
|
||||
};
|
||||
}
|
||||
|
||||
onResizeEnd(func: (e: MouseEvent, direction: string, node: any) => any) {
|
||||
this.emitter.on('resizeEnd', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('resizeEnd', func);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// new DragResizeEngine();
|
||||
@ -1,29 +1,28 @@
|
||||
import { Component } from 'react';
|
||||
import { observer } from '@ali/lowcode-globals';
|
||||
import { BorderHovering } from './border-hovering';
|
||||
import { SimulatorContext } from '../context';
|
||||
import { observer } from '@ali/lowcode-editor-core';
|
||||
import { BorderDetecting } from './border-detecting';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
import { BorderSelecting } from './border-selecting';
|
||||
import BorderResizing from './border-resizing';
|
||||
import { InsertionView } from './insertion';
|
||||
import './bem-tools.less';
|
||||
import './borders.less';
|
||||
|
||||
@observer
|
||||
export class BemTools extends Component {
|
||||
static contextType = SimulatorContext;
|
||||
|
||||
export class BemTools extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const host = this.context as BuiltinSimulatorHost;
|
||||
const host = this.props.host;
|
||||
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" />
|
||||
<BorderDetecting key="hovering" host={host} />
|
||||
<BorderSelecting key="selecting" host={host} />
|
||||
<InsertionView key="insertion" host={host} />
|
||||
<BorderResizing key="resizing" host={host} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component } from 'react';
|
||||
import { computed, observer } from '@ali/lowcode-globals';
|
||||
import { computed, observer } from '@ali/lowcode-editor-core';
|
||||
import { SimulatorContext } from '../context';
|
||||
import { BuiltinSimulatorHost } from '../host';
|
||||
import {
|
||||
@ -10,7 +10,7 @@ import {
|
||||
isVertical
|
||||
} from '../../designer';
|
||||
import { ISimulatorHost, } from '../../simulator';
|
||||
import {NodeParent } from '../../document';
|
||||
import { ParentalNode } from '../../document';
|
||||
import './insertion.less';
|
||||
|
||||
interface InsertionData {
|
||||
@ -24,7 +24,7 @@ interface InsertionData {
|
||||
/**
|
||||
* 处理拖拽子节点(INode)情况
|
||||
*/
|
||||
function processChildrenDetail(sim: ISimulatorHost, container: NodeParent, detail: LocationChildrenDetail): InsertionData {
|
||||
function processChildrenDetail(sim: ISimulatorHost, container: ParentalNode, detail: LocationChildrenDetail): InsertionData {
|
||||
let edge = detail.edge || null;
|
||||
|
||||
if (!edge) {
|
||||
@ -106,30 +106,25 @@ function processDetail({ target, detail, document }: DropLocation): InsertionDat
|
||||
if (!instances) {
|
||||
return {};
|
||||
}
|
||||
const edge = sim.computeComponentInstanceRect(instances[0], target.componentMeta.rectSelector);
|
||||
const edge = sim.computeComponentInstanceRect(instances[0], target.componentMeta.rootSelector);
|
||||
return edge ? { edge, insertType: 'cover', coverRect: edge } : {};
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
export class InsertionView extends Component {
|
||||
static contextType = SimulatorContext;
|
||||
|
||||
@computed get host(): BuiltinSimulatorHost {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const loc = this.host.document.dropLocation;
|
||||
const { host } = this.props;
|
||||
const loc = host.document.dropLocation;
|
||||
if (!loc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { scale, scrollX, scrollY } = this.host.viewport;
|
||||
const { scale, scrollX, scrollY } = host.viewport;
|
||||
const { edge, insertType, coverRect, nearRect, vertical } = processDetail(loc);
|
||||
|
||||
if (!edge) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// NOTE: 仅用作类型标注,切勿作为实体使用
|
||||
import { BuiltinSimulatorHost } from './host';
|
||||
import { AssetLevel, AssetLevels, AssetList, isAssetBundle, isAssetItem, AssetType, assetItem } from '@ali/lowcode-globals';
|
||||
import { isCSSUrl } from '@ali/lowcode-globals';
|
||||
import { AssetLevel, AssetLevels, AssetList, isAssetBundle, isAssetItem, AssetType, assetItem } from '@ali/lowcode-utils';
|
||||
import { isCSSUrl } from '@ali/lowcode-utils';
|
||||
import { BuiltinSimulatorRenderer } from './renderer';
|
||||
|
||||
export function createSimulator(
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component } from 'react';
|
||||
import { observer } from '@ali/lowcode-globals';
|
||||
import { observer } from '@ali/lowcode-editor-core';
|
||||
import { BuiltinSimulatorHost, BuiltinSimulatorProps } from './host';
|
||||
import { DocumentModel } from '../document';
|
||||
import { SimulatorContext } from './context';
|
||||
@ -38,23 +38,19 @@ export class BuiltinSimulatorHostView extends Component<SimulatorHostProps> {
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const { Provider } = SimulatorContext;
|
||||
return (
|
||||
<div className="lc-simulator">
|
||||
<Provider value={this.host}>
|
||||
{/*progressing.visible ? <PreLoaderView /> : null*/}
|
||||
<Canvas />
|
||||
</Provider>
|
||||
{/*progressing.visible ? <PreLoaderView /> : null*/}
|
||||
<Canvas host={this.host} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@observer
|
||||
class Canvas extends Component {
|
||||
static contextType = SimulatorContext;
|
||||
class Canvas extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
render() {
|
||||
const sim = this.context as BuiltinSimulatorHost;
|
||||
const sim = this.props.host;
|
||||
let className = 'lc-simulator-canvas';
|
||||
if (sim.deviceClassName) {
|
||||
className += ` ${sim.deviceClassName}`;
|
||||
@ -65,8 +61,8 @@ class Canvas extends Component {
|
||||
return (
|
||||
<div className={className}>
|
||||
<div ref={elmt => sim.mountViewport(elmt)} className="lc-simulator-canvas-viewport">
|
||||
<BemTools />
|
||||
<Content />
|
||||
<BemTools host={sim} />
|
||||
<Content host={sim} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -74,10 +70,9 @@ class Canvas extends Component {
|
||||
}
|
||||
|
||||
@observer
|
||||
class Content extends Component {
|
||||
static contextType = SimulatorContext;
|
||||
class Content extends Component<{ host: BuiltinSimulatorHost }> {
|
||||
render() {
|
||||
const sim = this.context as BuiltinSimulatorHost;
|
||||
const sim = this.props.host;
|
||||
const viewport = sim.viewport;
|
||||
let frameStyle = {};
|
||||
if (viewport.scale < 1) {
|
||||
|
||||
@ -31,12 +31,13 @@
|
||||
|
||||
&-device-iphone6 {
|
||||
left: 50%;
|
||||
width: 368px;
|
||||
width: 378px;
|
||||
transform: translateX(-50%);
|
||||
background: url(https://img.alicdn.com/tps/TB12GetLpXXXXXhXFXXXXXXXXXX-756-1544.png) no-repeat top;
|
||||
background-size: 378px 772px;
|
||||
top: 8px;
|
||||
.@{scope}-canvas-viewport {
|
||||
width: auto;
|
||||
top: 114px;
|
||||
left: 25px;
|
||||
right: 25px;
|
||||
@ -46,12 +47,12 @@
|
||||
}
|
||||
|
||||
&-device-default {
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
left: 15px;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
left: 16px;
|
||||
width: auto;
|
||||
box-shadow: 0 2px 10px 0 rgba(31,56,88,.15);
|
||||
box-shadow: 0 1px 4px 0 rgba(31, 50, 88, 0.125);
|
||||
}
|
||||
|
||||
&-content {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { obx, autorun, computed } from '@ali/lowcode-globals';
|
||||
import { obx, autorun, computed, getPublicPath, hotkey, focusTracker } from '@ali/lowcode-editor-core';
|
||||
import { ISimulatorHost, Component, NodeInstance, ComponentInstance } from '../simulator';
|
||||
import Viewport from './viewport';
|
||||
import { createSimulator } from './create-simulator';
|
||||
import { Node, NodeParent, DocumentModel, isNodeParent, isNode, contains, isRootNode } from '../document';
|
||||
import { Node, ParentalNode, DocumentModel, isNode, contains, isRootNode } from '../document';
|
||||
import ResourceConsumer from './resource-consumer';
|
||||
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType, getPublicPath } from '@ali/lowcode-globals';
|
||||
import { AssetLevel, Asset, AssetList, assetBundle, assetItem, AssetType, isElement, isFormEvent } from '@ali/lowcode-utils';
|
||||
import {
|
||||
DragObjectType,
|
||||
isShaken,
|
||||
@ -20,29 +20,29 @@ import {
|
||||
getRectTarget,
|
||||
Rect,
|
||||
CanvasPoint,
|
||||
hotkey,
|
||||
} from '../designer';
|
||||
import { parseProps } from './utils/parse-props';
|
||||
import { isElement } from '@ali/lowcode-globals';
|
||||
import { ComponentMetadata } from '@ali/lowcode-globals';
|
||||
import { parseMetadata } from './utils/parse-metadata';
|
||||
import { ComponentMetadata, ComponentSchema } from '@ali/lowcode-types';
|
||||
import { BuiltinSimulatorRenderer } from './renderer';
|
||||
import clipboard from '../designer/clipboard';
|
||||
import { LiveEditing } from './live-editing/live-editing';
|
||||
|
||||
export interface LibraryItem {
|
||||
package: string;
|
||||
library: string;
|
||||
urls: Asset;
|
||||
urls?: Asset;
|
||||
}
|
||||
|
||||
export interface BuiltinSimulatorProps {
|
||||
// 从 documentModel 上获取
|
||||
// suspended?: boolean;
|
||||
designMode?: 'live' | 'design' | 'mock' | 'extend' | 'border' | 'preview';
|
||||
designMode?: 'live' | 'design' | 'preview' | 'extend' | 'border';
|
||||
device?: 'mobile' | 'iphone' | string;
|
||||
deviceClassName?: string;
|
||||
simulatorUrl?: Asset;
|
||||
environment?: Asset;
|
||||
extraEnvironment?: Asset;
|
||||
library?: LibraryItem[];
|
||||
simulatorUrl?: Asset;
|
||||
theme?: Asset;
|
||||
componentsAsset?: Asset;
|
||||
[key: string]: any;
|
||||
@ -55,7 +55,7 @@ const defaultSimulatorUrl = (() => {
|
||||
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`];
|
||||
urls = [`${prefix}/react-simulator-renderer.css`, `${prefix}/react-simulator-renderer.js`];
|
||||
} else {
|
||||
urls = [`${prefix}/react-simulator-renderer.css`, `${prefix}/react-simulator-renderer.js`];
|
||||
}
|
||||
@ -78,9 +78,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
readonly designer = this.document.designer;
|
||||
|
||||
@computed get device(): string | undefined {
|
||||
// 根据 device 不同来做画布外框样式变化 渲染时可选择不同组件
|
||||
// renderer 依赖
|
||||
@computed get device(): string {
|
||||
return this.get('device') || 'default';
|
||||
}
|
||||
|
||||
@ -88,7 +86,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return this.get('deviceClassName');
|
||||
}
|
||||
|
||||
@computed get designMode(): 'live' | 'design' | 'extend' | 'border' | 'preview' {
|
||||
@computed get designMode(): 'live' | 'design' | 'preview' {
|
||||
// renderer 依赖
|
||||
// TODO: 需要根据 design mode 不同切换鼠标响应情况
|
||||
return this.get('designMode') || 'design';
|
||||
@ -180,7 +178,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
if (library) {
|
||||
library.forEach((item) => {
|
||||
this.libraryMap[item.package] = item.library;
|
||||
libraryAsset.push(item.urls);
|
||||
if (item.urls) {
|
||||
libraryAsset.push(item.urls);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -188,6 +188,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
// required & use once
|
||||
assetBundle(this.get('environment') || defaultEnvironment, AssetLevel.Environment),
|
||||
// required & use once
|
||||
assetBundle(this.get('extraEnvironment'), AssetLevel.Environment),
|
||||
// required & use once
|
||||
assetBundle(libraryAsset, AssetLevel.Library),
|
||||
// required & TODO: think of update
|
||||
assetBundle(this.theme, AssetLevel.Theme),
|
||||
@ -216,6 +218,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
// bind hotkey & clipboard
|
||||
hotkey.mount(this._contentWindow);
|
||||
focusTracker.mount(this._contentWindow);
|
||||
clipboard.injectCopyPaster(this._contentDocument);
|
||||
// TODO: dispose the bindings
|
||||
}
|
||||
@ -225,7 +228,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
// just listen special callback
|
||||
// because iframe maybe reload
|
||||
this.setupDragAndClick();
|
||||
this.setupHovering();
|
||||
this.setupDetecting();
|
||||
this.setupLiveEditing();
|
||||
this.setupContextMenu();
|
||||
}
|
||||
|
||||
setupDragAndClick() {
|
||||
@ -239,10 +244,18 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
doc.addEventListener(
|
||||
'mousedown',
|
||||
(downEvent: MouseEvent) => {
|
||||
// fix for popups close logic
|
||||
document.dispatchEvent(new Event('mousedown'));
|
||||
if (this.liveEditing.editing) {
|
||||
return;
|
||||
}
|
||||
// stop response document focus event
|
||||
downEvent.stopPropagation();
|
||||
downEvent.preventDefault();
|
||||
|
||||
// FIXME: dirty fix remove label-for fro liveEditing
|
||||
(downEvent.target as HTMLElement).removeAttribute('for');
|
||||
|
||||
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
|
||||
const node = nodeInst?.node || this.document.rootNode;
|
||||
const isMulti = downEvent.metaKey || downEvent.ctrlKey;
|
||||
@ -251,11 +264,20 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
doc.removeEventListener('mouseup', checkSelect, true);
|
||||
if (!isShaken(downEvent, e)) {
|
||||
const id = node.id;
|
||||
designer.activeTracker.track(node);
|
||||
designer.activeTracker.track({ node, instance: nodeInst?.instance });
|
||||
if (isMulti && !isRootNode(node) && selection.has(id)) {
|
||||
selection.remove(id);
|
||||
} else {
|
||||
selection.select(id);
|
||||
const editor = this.designer?.editor;
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.builtinSimulator.select', {
|
||||
selected,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -266,7 +288,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
if (isMulti) {
|
||||
// multi select mode, directily add
|
||||
if (!selection.has(node.id)) {
|
||||
designer.activeTracker.track(node);
|
||||
designer.activeTracker.track({ node, instance: nodeInst?.instance });
|
||||
selection.add(node.id);
|
||||
ignoreUpSelected = true;
|
||||
}
|
||||
@ -299,43 +321,38 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
doc.addEventListener(
|
||||
'click',
|
||||
(e) => {
|
||||
// fix for popups close logic
|
||||
const x = new Event('click');
|
||||
x.initEvent('click', true);
|
||||
this._iframe?.dispatchEvent(x);
|
||||
const target = e.target as HTMLElement;
|
||||
if (isFormEvent(e) || target?.closest('.next-input-group,.next-checkbox-group,.next-date-picker,.next-input,.next-month-picker,.next-number-picker,.next-radio-group,.next-range,.next-range-picker,.next-rating,.next-select,.next-switch,.next-time-picker,.next-upload,.next-year-picker,.next-breadcrumb-item,.next-calendar-header,.next-calendar-table')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
// stop response document click event
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// todo: catch link redirect
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
// cause edit
|
||||
doc.addEventListener(
|
||||
'dblclick',
|
||||
(e: MouseEvent) => {
|
||||
// stop response document dblclick event
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
// todo: quick editing
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
private disableHovering?: () => void;
|
||||
/**
|
||||
* 设置悬停处理
|
||||
*/
|
||||
setupHovering() {
|
||||
setupDetecting() {
|
||||
const doc = this.contentDocument!;
|
||||
const hovering = this.document.designer.hovering;
|
||||
const detecting = this.document.designer.detecting;
|
||||
const hover = (e: MouseEvent) => {
|
||||
if (!hovering.enable) {
|
||||
if (!detecting.enable) {
|
||||
return;
|
||||
}
|
||||
const nodeInst = this.getNodeInstanceFromElement(e.target as Element);
|
||||
hovering.hover(nodeInst?.node || null);
|
||||
detecting.capture(nodeInst?.node || null);
|
||||
e.stopPropagation();
|
||||
};
|
||||
const leave = () => hovering.leave(this.document);
|
||||
const leave = () => detecting.leave(this.document);
|
||||
|
||||
doc.addEventListener('mouseover', hover, true);
|
||||
doc.addEventListener('mouseleave', leave, false);
|
||||
@ -350,13 +367,47 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
);
|
||||
|
||||
this.disableHovering = () => {
|
||||
hovering.leave(this.document);
|
||||
detecting.leave(this.document);
|
||||
doc.removeEventListener('mouseover', hover, true);
|
||||
doc.removeEventListener('mouseleave', leave, false);
|
||||
this.disableHovering = undefined;
|
||||
};
|
||||
}
|
||||
|
||||
readonly liveEditing = new LiveEditing();
|
||||
setupLiveEditing() {
|
||||
const doc = this.contentDocument!;
|
||||
// cause edit
|
||||
doc.addEventListener(
|
||||
'dblclick',
|
||||
(e: MouseEvent) => {
|
||||
// stop response document dblclick event
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
const targetElement = e.target as HTMLElement;
|
||||
const nodeInst = this.getNodeInstanceFromElement(targetElement);
|
||||
if (!nodeInst) {
|
||||
return;
|
||||
}
|
||||
const node = nodeInst.node || this.document.rootNode;
|
||||
|
||||
const rootElement = this.findDOMNodes(nodeInst.instance, node.componentMeta.rootSelector)?.find(item => item.contains(targetElement)) as HTMLElement;
|
||||
if (!rootElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.liveEditing.apply({
|
||||
node,
|
||||
rootElement,
|
||||
event: e,
|
||||
});
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
@ -369,11 +420,35 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
} else {
|
||||
// weekup some autorun reaction
|
||||
if (!this.disableHovering) {
|
||||
this.setupHovering();
|
||||
this.setupDetecting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupContextMenu() {
|
||||
const doc = this.contentDocument!;
|
||||
doc.addEventListener('contextmenu', (e: MouseEvent) => {
|
||||
const targetElement = e.target as HTMLElement;
|
||||
const nodeInst = this.getNodeInstanceFromElement(targetElement);
|
||||
if (!nodeInst) {
|
||||
return;
|
||||
}
|
||||
const node = nodeInst.node || this.document.rootNode;
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
const editor = this.designer?.editor;
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('desiger.builtinSimulator.contextmenu', {
|
||||
selected,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
@ -388,16 +463,19 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
const component = this.getComponent(componentName);
|
||||
|
||||
if (component) {
|
||||
parseProps(component as any);
|
||||
if (!component) {
|
||||
return {
|
||||
componentName,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 1. generate builtin div/p/h1/h2
|
||||
// 2. read propTypes
|
||||
|
||||
return {
|
||||
componentName,
|
||||
props: parseProps(this.getComponent(componentName)),
|
||||
...parseMetadata(component),
|
||||
};
|
||||
}
|
||||
|
||||
@ -408,6 +486,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return this.renderer?.getComponent(componentName) || null;
|
||||
}
|
||||
|
||||
createComponent(schema: ComponentSchema): Component | null {
|
||||
return this.renderer?.createComponent(schema) || null;
|
||||
}
|
||||
|
||||
@obx.val private instancesMap = new Map<string, ComponentInstance[]>();
|
||||
setInstance(id: string, instances: ComponentInstance[] | null) {
|
||||
if (instances == null) {
|
||||
@ -453,7 +535,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
if (!instances) {
|
||||
return null;
|
||||
}
|
||||
return this.computeComponentInstanceRect(instances[0], node.componentMeta.rectSelector);
|
||||
return this.computeComponentInstanceRect(instances[0], node.componentMeta.rootSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -461,19 +543,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
*/
|
||||
computeComponentInstanceRect(instance: ComponentInstance, selector?: string): Rect | null {
|
||||
const renderer = this.renderer!;
|
||||
const elements = renderer.findDOMNodes(instance);
|
||||
const elements = this.findDOMNodes(instance, selector);
|
||||
if (!elements) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let elems = elements.slice();
|
||||
if (selector) {
|
||||
const matched = getMatched(elems, selector);
|
||||
if (!matched) {
|
||||
return null;
|
||||
}
|
||||
elems = [matched];
|
||||
}
|
||||
const elems = elements.slice();
|
||||
let rects: DOMRect[] | undefined;
|
||||
let last: { x: number; y: number; r: number; b: number } | undefined;
|
||||
let computed = false;
|
||||
@ -532,8 +607,20 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* @see ISimulator
|
||||
*/
|
||||
findDOMNodes(instance: ComponentInstance): Array<Element | Text> | null {
|
||||
return this._renderer?.findDOMNodes(instance) || null;
|
||||
findDOMNodes(instance: ComponentInstance, selector?: string): Array<Element | Text> | null {
|
||||
const elements = this._renderer?.findDOMNodes(instance);
|
||||
if (!elements) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (selector) {
|
||||
const matched = getMatched(elements, selector);
|
||||
if (!matched) {
|
||||
return null;
|
||||
}
|
||||
return [matched];
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -705,7 +792,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
this.sensing = true;
|
||||
this.scroller.scrolling(e);
|
||||
const dropContainer = this.getDropContainer(e);
|
||||
if (!dropContainer) {
|
||||
if (!dropContainer ||
|
||||
// too dirty
|
||||
(typeof dropContainer.container?.componentMeta?.prototype?.options?.canDropIn === 'function' &&
|
||||
!dropContainer.container?.componentMeta?.prototype?.options?.canDropIn(e.dragObject.nodes[0]))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -715,7 +805,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
|
||||
const { container, instance: containerInstance } = dropContainer;
|
||||
|
||||
const edge = this.computeComponentInstanceRect(containerInstance, container.componentMeta.rectSelector);
|
||||
const edge = this.computeComponentInstanceRect(containerInstance, container.componentMeta.rootSelector);
|
||||
|
||||
if (!edge) {
|
||||
return null;
|
||||
@ -736,6 +826,15 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
event: e,
|
||||
};
|
||||
|
||||
if (e.dragObject.nodes[0].getPrototype().isModal()) {
|
||||
return this.designer.createLocation({
|
||||
target: this.document.rootNode,
|
||||
detail,
|
||||
source: 'simulator' + this.document.id,
|
||||
event: e,
|
||||
});
|
||||
}
|
||||
|
||||
if (!children || children.size < 1 || !edge) {
|
||||
return this.designer.createLocation(locationData);
|
||||
}
|
||||
@ -756,7 +855,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
? instances.find((inst) => this.getClosestNodeInstance(inst, container.id)?.instance === containerInstance)
|
||||
: instances[0]
|
||||
: null;
|
||||
const rect = inst ? this.computeComponentInstanceRect(inst, node.componentMeta.rectSelector) : null;
|
||||
const rect = inst ? this.computeComponentInstanceRect(inst, node.componentMeta.rootSelector) : null;
|
||||
|
||||
if (!rect) {
|
||||
continue;
|
||||
@ -855,7 +954,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
container = currentRoot;
|
||||
}
|
||||
|
||||
if (!isNodeParent(container)) {
|
||||
if (!container.isParental()) {
|
||||
container = container.parent || currentRoot;
|
||||
}
|
||||
|
||||
@ -944,7 +1043,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return null;
|
||||
}
|
||||
|
||||
isAcceptable(container: NodeParent): boolean {
|
||||
isAcceptable(container: ParentalNode): boolean {
|
||||
return false;
|
||||
/*
|
||||
const meta = container.componentMeta;
|
||||
@ -965,7 +1064,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
return this.document.checkDropTarget(container, dragObject as any);
|
||||
}
|
||||
|
||||
const meta = container.componentMeta;
|
||||
const meta = (container as Node).componentMeta;
|
||||
|
||||
// FIXME: get containerInstance for accept logic use
|
||||
const acceptable: boolean = this.isAcceptable(container);
|
||||
@ -1007,7 +1106,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
||||
/**
|
||||
* 查找邻近容器
|
||||
*/
|
||||
getNearByContainer(container: NodeParent, e: LocateEvent) {
|
||||
getNearByContainer(container: ParentalNode, e: LocateEvent) {
|
||||
/*
|
||||
const children = container.children;
|
||||
if (!children || children.length < 1) {
|
||||
@ -1111,6 +1210,6 @@ function getMatched(elements: Array<Element | Text>, selector: string): Element
|
||||
}
|
||||
|
||||
interface DropContainer {
|
||||
container: NodeParent;
|
||||
container: ParentalNode;
|
||||
instance: ComponentInstance;
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export * from './host';
|
||||
export * from './host-view';
|
||||
export * from './renderer';
|
||||
export * from './live-editing/live-editing';
|
||||
|
||||
@ -0,0 +1,220 @@
|
||||
import { obx, globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||
import { LiveTextEditingConfig } from '@ali/lowcode-types';
|
||||
import { Node, Prop } from '../../document';
|
||||
|
||||
const EDITOR_KEY = 'data-setter-prop';
|
||||
|
||||
function getSetterPropElement(ele: HTMLElement, root: HTMLElement): HTMLElement | null {
|
||||
const box = ele.closest(`[${EDITOR_KEY}]`);
|
||||
if (!box || !root.contains(box)) {
|
||||
return null;
|
||||
}
|
||||
return box as HTMLElement;
|
||||
}
|
||||
|
||||
function defaultSaveContent(content: string, prop: Prop) {
|
||||
prop.setValue(content);
|
||||
}
|
||||
|
||||
export interface EditingTarget {
|
||||
node: Node;
|
||||
rootElement: HTMLElement;
|
||||
event: MouseEvent;
|
||||
}
|
||||
|
||||
const saveHandlers: SaveHandler[] = [];
|
||||
function addLiveEditingSaveHandler(handler: SaveHandler) {
|
||||
saveHandlers.push(handler);
|
||||
}
|
||||
|
||||
const specificRules: SpecificRule[] = [];
|
||||
function addLiveEditingSpecificRule(rule: SpecificRule) {
|
||||
specificRules.push(rule);
|
||||
}
|
||||
|
||||
export class LiveEditing {
|
||||
static addLiveEditingSpecificRule = addLiveEditingSpecificRule;
|
||||
static addLiveEditingSaveHandler = addLiveEditingSaveHandler;
|
||||
|
||||
@obx.ref private _editing: Prop | null = null;
|
||||
apply(target: EditingTarget) {
|
||||
const { node, event, rootElement } = target;
|
||||
const targetElement = event.target as HTMLElement;
|
||||
const liveTextEditing = node.componentMeta.liveTextEditing;
|
||||
|
||||
const editor = globalContext.get(Editor);
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';
|
||||
editor?.emit('designer.builinSimulator.LiveEditing', {
|
||||
selected,
|
||||
});
|
||||
|
||||
let setterPropElement = getSetterPropElement(targetElement, rootElement);
|
||||
let propTarget = setterPropElement?.dataset.setterProp;
|
||||
let matched: (LiveTextEditingConfig & { propElement?: HTMLElement; }) | undefined | null;
|
||||
if (liveTextEditing) {
|
||||
if (propTarget) {
|
||||
// 已埋点命中 data-setter-prop="proptarget", 从 liveTextEditing 读取配置(mode|onSaveContent)
|
||||
matched = liveTextEditing.find(config => config.propTarget == propTarget);
|
||||
} else {
|
||||
// 执行 embedTextEditing selector 规则,获得第一个节点 是否 contains e.target,若匹配,读取配置
|
||||
matched = liveTextEditing.find(config => {
|
||||
if (!config.selector) {
|
||||
return false;
|
||||
}
|
||||
setterPropElement = queryPropElement(rootElement, targetElement, config.selector);
|
||||
return setterPropElement ? true : false;
|
||||
});
|
||||
propTarget = matched?.propTarget;
|
||||
}
|
||||
} else {
|
||||
specificRules.some((rule) => {
|
||||
matched = rule(target);
|
||||
return matched ? true : false;
|
||||
});
|
||||
if (matched) {
|
||||
propTarget = matched.propTarget;
|
||||
setterPropElement = matched.propElement || queryPropElement(rootElement, targetElement, matched.selector);
|
||||
}
|
||||
}
|
||||
|
||||
if (!propTarget) {
|
||||
// 自动纯文本编辑满足一下情况:
|
||||
// 1. children 内容都是 Leaf 且都是文本(一期)
|
||||
// 2. DOM 节点是单层容器,子集都是文本节点 (已满足)
|
||||
const isAllText = node.children?.every(item => {
|
||||
return item.isLeaf() && item.getProp('children')?.type === 'literal';
|
||||
});
|
||||
// TODO:
|
||||
}
|
||||
|
||||
if (propTarget && setterPropElement) {
|
||||
const prop = node.getProp(propTarget, true)!;
|
||||
|
||||
if (this._editing === prop) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 进入编辑
|
||||
// 1. 设置contentEditable="plaintext|..."
|
||||
// 2. 添加类名
|
||||
// 3. focus & cursor locate
|
||||
// 4. 监听 blur 事件
|
||||
// 5. 设置编辑锁定:disable hover | disable select | disable canvas drag
|
||||
|
||||
const onSaveContent = matched?.onSaveContent || saveHandlers.find(item => item.condition(prop))?.onSaveContent || defaultSaveContent;
|
||||
|
||||
setterPropElement.setAttribute('contenteditable', matched?.mode && matched.mode !== 'plaintext' ? 'true' : 'plaintext-only');
|
||||
setterPropElement.classList.add('engine-live-editing');
|
||||
// be sure
|
||||
setterPropElement.focus();
|
||||
setCaret(event);
|
||||
|
||||
this._save = () => {
|
||||
onSaveContent(setterPropElement!.innerText, prop);
|
||||
};
|
||||
|
||||
const keydown = (e: KeyboardEvent) => {
|
||||
console.info(e.code);
|
||||
switch (e.code) {
|
||||
case 'Enter':
|
||||
// TODO: check is richtext?
|
||||
case 'Escape':
|
||||
case 'Tab':
|
||||
setterPropElement?.blur();
|
||||
}
|
||||
// esc
|
||||
// enter
|
||||
// tab
|
||||
};
|
||||
const focusout = (e: FocusEvent) => {
|
||||
this.saveAndDispose();
|
||||
};
|
||||
setterPropElement.addEventListener('focusout', focusout);
|
||||
setterPropElement.addEventListener('keydown', keydown, true);
|
||||
|
||||
this._dispose = () => {
|
||||
setterPropElement!.classList.remove('engine-live-editing');
|
||||
setterPropElement!.removeAttribute('contenteditable');
|
||||
setterPropElement!.removeEventListener('focusout', focusout);
|
||||
setterPropElement!.removeEventListener('keydown', keydown, true);
|
||||
};
|
||||
|
||||
this._editing = prop;
|
||||
}
|
||||
|
||||
// TODO: process enter | esc events & joint the FocusTracker
|
||||
|
||||
// TODO: upward testing for b/i/a html elements
|
||||
|
||||
|
||||
}
|
||||
|
||||
get editing() {
|
||||
return this._editing;
|
||||
}
|
||||
|
||||
private _dispose?: () => void;
|
||||
private _save?: () => void;
|
||||
saveAndDispose() {
|
||||
if (this._save) {
|
||||
this._save();
|
||||
this._save = undefined;
|
||||
}
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this._dispose) {
|
||||
this._dispose();
|
||||
this._dispose = undefined;
|
||||
}
|
||||
this._editing = null;
|
||||
}
|
||||
}
|
||||
|
||||
export type SpecificRule = (target: EditingTarget) => (LiveTextEditingConfig & {
|
||||
propElement?: HTMLElement;
|
||||
}) | null;
|
||||
|
||||
export interface SaveHandler {
|
||||
condition: (prop: Prop) => boolean;
|
||||
onSaveContent: (content: string, prop: Prop) => void;
|
||||
}
|
||||
|
||||
function setCaret(event: MouseEvent) {
|
||||
const doc = event.view?.document!;
|
||||
const range = doc.caretRangeFromPoint(event.clientX, event.clientY);
|
||||
if (range) {
|
||||
selectRange(doc, range);
|
||||
setTimeout(() => selectRange(doc, range), 1);
|
||||
}
|
||||
}
|
||||
|
||||
function selectRange(doc: Document, range: Range) {
|
||||
const selection = doc.getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function queryPropElement(rootElement: HTMLElement, targetElement: HTMLElement, selector?: string) {
|
||||
if (!selector) {
|
||||
return null;
|
||||
}
|
||||
let propElement = selector === ':root' ? rootElement : rootElement.querySelector(selector);
|
||||
if (!propElement) {
|
||||
return null;
|
||||
}
|
||||
if (!propElement.contains(targetElement)) {
|
||||
// try selectorAll
|
||||
propElement = Array.from(rootElement.querySelectorAll(selector)).find(item => item.contains(targetElement)) as HTMLElement;
|
||||
if (!propElement) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return propElement as HTMLElement;
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
@import '~@ali/ve-less-variables/index.less';
|
||||
|
||||
// 样式直接沿用之前的样式,优化了下命名
|
||||
.instance-node-selector {
|
||||
position: relative;
|
||||
margin-right: 2px;
|
||||
color: var(--color-icon-white, @title-bgcolor);
|
||||
border-radius: @global-border-radius;
|
||||
margin-right: 2px;
|
||||
pointer-events: auto;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 5px;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
max-width: inherit;
|
||||
path {
|
||||
fill: var(--color-icon-white, @title-bgcolor);
|
||||
}
|
||||
}
|
||||
&-current {
|
||||
background: var(--color-brand, @brand-color-1);
|
||||
padding: 0 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
color: var(--color-icon-white, @title-bgcolor);
|
||||
border-radius: 3px;
|
||||
|
||||
&-title {
|
||||
padding-right: 6px;
|
||||
color: var(--color-icon-white, @title-bgcolor);
|
||||
}
|
||||
}
|
||||
&-list {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
&-node {
|
||||
margin: 2px 0;
|
||||
&-content {
|
||||
padding-left: 6px;
|
||||
background: #78869a;
|
||||
display: inline-flex;
|
||||
border-radius: 3px;
|
||||
align-items: center;
|
||||
height: 20px;
|
||||
color: var(--color-icon-white, @title-bgcolor);
|
||||
cursor: pointer;
|
||||
overflow: visible;
|
||||
}
|
||||
&-title {
|
||||
padding-right: 6px;
|
||||
// margin-left: 5px;
|
||||
color: var(--color-icon-white, @title-bgcolor);
|
||||
cursor: pointer;
|
||||
overflow: visible;
|
||||
}
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.instance-node-selector-current {
|
||||
color: ar(--color-text-reverse, @white-alpha-2);
|
||||
}
|
||||
.instance-node-selector-popup {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: 0.2s all ease-in;
|
||||
}
|
||||
}
|
||||
121
packages/designer/src/builtin-simulator/node-selector/index.tsx
Normal file
121
packages/designer/src/builtin-simulator/node-selector/index.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import { Overlay } from '@alifd/next';
|
||||
import React from 'react';
|
||||
import { Title, globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||
import './index.less';
|
||||
|
||||
import { Node, ParentalNode } from '@ali/lowcode-designer';
|
||||
|
||||
const { Popup } = Overlay;
|
||||
|
||||
export interface IProps {
|
||||
node: Node;
|
||||
}
|
||||
|
||||
export interface IState {
|
||||
parentNodes: Node[];
|
||||
}
|
||||
|
||||
type UnionNode = Node | ParentalNode | null;
|
||||
|
||||
export default class InstanceNodeSelector extends React.Component<IProps, IState> {
|
||||
state: IState = {
|
||||
parentNodes: [],
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const parentNodes = this.getParentNodes(this.props.node);
|
||||
this.setState({
|
||||
parentNodes,
|
||||
});
|
||||
}
|
||||
|
||||
// 获取节点的父级节点(最多获取5层)
|
||||
getParentNodes = (node: Node) => {
|
||||
const parentNodes = [];
|
||||
let currentNode: UnionNode = node;
|
||||
|
||||
while (currentNode && parentNodes.length < 5) {
|
||||
currentNode = currentNode.getParent();
|
||||
if (currentNode) {
|
||||
parentNodes.push(currentNode);
|
||||
}
|
||||
}
|
||||
return parentNodes;
|
||||
};
|
||||
|
||||
onSelect = (node: Node) => () => {
|
||||
if (node && typeof node.select === 'function') {
|
||||
node.select();
|
||||
const editor = globalContext.get(Editor);
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
editor?.emit('designer.border.action', {
|
||||
name: 'select',
|
||||
selected,
|
||||
});
|
||||
}
|
||||
};
|
||||
onMouseOver = (node: Node) => (_: any, flag = true) => {
|
||||
if (node && typeof node.hover === 'function') {
|
||||
node.hover(flag);
|
||||
}
|
||||
};
|
||||
onMouseOut = (node: Node) => (_: any, flag = false) => {
|
||||
if (node && typeof node.hover === 'function') {
|
||||
node.hover(flag);
|
||||
}
|
||||
};
|
||||
renderNodes = (node: Node) => {
|
||||
const nodes = this.state.parentNodes || [];
|
||||
const children = nodes.map((node, key) => {
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
onClick={this.onSelect(node)}
|
||||
onMouseEnter={this.onMouseOver(node)}
|
||||
onMouseLeave={this.onMouseOut(node)}
|
||||
className="instance-node-selector-node"
|
||||
>
|
||||
<div className="instance-node-selector-node-content">
|
||||
<Title
|
||||
className="instance-node-selector-node-title"
|
||||
title={{
|
||||
label: node.title,
|
||||
icon: node.icon,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return children;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { node } = this.props;
|
||||
return (
|
||||
<div className="instance-node-selector">
|
||||
<Popup
|
||||
trigger={
|
||||
<div className="instance-node-selector-current">
|
||||
<Title
|
||||
className="instance-node-selector-node-title"
|
||||
title={{
|
||||
label: node.title,
|
||||
icon: node.icon,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
triggerType="hover"
|
||||
offset={[0, 2]}
|
||||
>
|
||||
<div className="instance-node-selector">{this.renderNodes(node)}</div>
|
||||
</Popup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
import { ComponentInstance, NodeInstance, Component } from '../simulator';
|
||||
import { ComponentSchema } from '@ali/lowcode-types';
|
||||
|
||||
export interface BuiltinSimulatorRenderer {
|
||||
readonly isSimulatorRenderer: true;
|
||||
createComponent(schema: ComponentSchema): Component | null;
|
||||
getComponent(componentName: string): Component;
|
||||
getComponentInstances(id: string): ComponentInstance[] | null;
|
||||
getClosestNodeInstance(from: ComponentInstance, nodeId?: string): NodeInstance<ComponentInstance> | null;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { autorun, obx } from '@ali/lowcode-globals';
|
||||
import { autorun, obx } from '@ali/lowcode-editor-core';
|
||||
import { BuiltinSimulatorHost } from './host';
|
||||
import { EventEmitter } from 'events';
|
||||
import { BuiltinSimulatorRenderer, isSimulatorRenderer } from './renderer';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { isValidElement } from 'react';
|
||||
import { isElement } from '@ali/lowcode-globals';
|
||||
import { PropConfig } from '@ali/lowcode-globals';
|
||||
import { isElement } from '@ali/lowcode-utils';
|
||||
import { PropConfig } from '@ali/lowcode-types';
|
||||
|
||||
export const primitiveTypes = [
|
||||
'string',
|
||||
@ -198,3 +198,10 @@ export function parseProps(component: any): PropConfig[] {
|
||||
|
||||
return Object.keys(result).map(key => result[key]);
|
||||
}
|
||||
|
||||
export function parseMetadata(component: any): any {
|
||||
return {
|
||||
props: parseProps(component),
|
||||
...component.componentMetadata,
|
||||
};
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { obx, computed } from '@ali/lowcode-globals';
|
||||
import { obx, computed } from '@ali/lowcode-editor-core';
|
||||
import { Point, ScrollTarget } from '../designer';
|
||||
import { AutoFit, IViewport } from '../simulator';
|
||||
|
||||
|
||||
@ -6,24 +6,32 @@ import {
|
||||
ComponentAction,
|
||||
TitleContent,
|
||||
TransformedComponentMetadata,
|
||||
getRegisteredMetadataTransducers,
|
||||
registerMetadataTransducer,
|
||||
computed,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { Node, NodeParent } from './document';
|
||||
NestingFilter,
|
||||
isTitleConfig,
|
||||
I18nData,
|
||||
LiveTextEditingConfig,
|
||||
FieldConfig,
|
||||
} from '@ali/lowcode-types';
|
||||
import { computed } from '@ali/lowcode-editor-core';
|
||||
import { Node, ParentalNode, TransformStage } from './document';
|
||||
import { Designer } from './designer';
|
||||
import { intl } from './locale';
|
||||
import { intlNode } 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';
|
||||
import { ReactElement } from 'react';
|
||||
import { IconHidden } from './icons/hidden';
|
||||
|
||||
function ensureAList(list?: string | string[]): string[] | null {
|
||||
if (!list) {
|
||||
return null;
|
||||
}
|
||||
if (!Array.isArray(list)) {
|
||||
if (typeof list !== 'string') {
|
||||
return null;
|
||||
}
|
||||
list = list.split(/ *[ ,|] */).filter(Boolean);
|
||||
}
|
||||
if (list.length < 1) {
|
||||
@ -32,44 +40,29 @@ function ensureAList(list?: string | string[]): string[] | 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);
|
||||
}
|
||||
}
|
||||
function isRegExp(obj: any): obj is RegExp {
|
||||
return obj && obj.test && obj.exec && obj.compile;
|
||||
}
|
||||
|
||||
let uri = pkg.join('/');
|
||||
uri += `:${npm.destructuring && npm.exportName ? npm.exportName : 'default'}`;
|
||||
|
||||
if (npm.subName) {
|
||||
uri += `.${npm.subName}`;
|
||||
function buildFilter(rule?: string | string[] | RegExp | NestingFilter) {
|
||||
if (!rule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return uri;
|
||||
if (typeof rule === 'function') {
|
||||
return rule;
|
||||
}
|
||||
if (isRegExp(rule)) {
|
||||
return (testNode: Node | NodeSchema) => rule.test(testNode.componentName);
|
||||
}
|
||||
const list = ensureAList(rule);
|
||||
if (!list) {
|
||||
return null;
|
||||
}
|
||||
return (testNode: Node | NodeSchema) => list.includes(testNode.componentName);
|
||||
}
|
||||
|
||||
export class ComponentMeta {
|
||||
readonly isComponentMeta = true;
|
||||
private _uri?: string;
|
||||
get uri(): string {
|
||||
return this._uri!;
|
||||
}
|
||||
private _npm?: NpmInfo;
|
||||
get npm() {
|
||||
return this._npm;
|
||||
@ -90,9 +83,9 @@ export class ComponentMeta {
|
||||
get descriptor(): string | undefined {
|
||||
return this._descriptor;
|
||||
}
|
||||
private _rectSelector?: string;
|
||||
get rectSelector(): string | undefined {
|
||||
return this._rectSelector;
|
||||
private _rootSelector?: string;
|
||||
get rootSelector(): string | undefined {
|
||||
return this._rootSelector;
|
||||
}
|
||||
private _transformedMetadata?: TransformedComponentMetadata;
|
||||
get configure() {
|
||||
@ -100,16 +93,29 @@ export class ComponentMeta {
|
||||
return config?.combined || config?.props || [];
|
||||
}
|
||||
|
||||
private parentWhitelist?: string[] | null;
|
||||
private childWhitelist?: string[] | null;
|
||||
private _liveTextEditing?: LiveTextEditingConfig[];
|
||||
get liveTextEditing() {
|
||||
return this._liveTextEditing;
|
||||
}
|
||||
|
||||
private parentWhitelist?: NestingFilter | null;
|
||||
private childWhitelist?: NestingFilter | null;
|
||||
|
||||
private _title?: TitleContent;
|
||||
get title() {
|
||||
get title(): string | I18nData | ReactElement {
|
||||
// TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。
|
||||
// string | i18nData | ReactElement
|
||||
// TitleConfig title.label
|
||||
if (isTitleConfig(this._title)) {
|
||||
return (this._title.label as any) || this.componentName;
|
||||
}
|
||||
return this._title || this.componentName;
|
||||
}
|
||||
|
||||
@computed get icon() {
|
||||
// TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。
|
||||
// give Slot default icon
|
||||
// if _title is TitleConfig get _title.icon
|
||||
return (
|
||||
this._transformedMetadata?.icon ||
|
||||
(this.componentName === 'Page' ? IconPage : this.isContainer ? IconContainer : IconComponent)
|
||||
@ -125,25 +131,52 @@ export class ComponentMeta {
|
||||
this.parseMetadata(metadata);
|
||||
}
|
||||
|
||||
setNpm(info: NpmInfo) {
|
||||
if (!this._npm) {
|
||||
this._npm = info;
|
||||
}
|
||||
}
|
||||
|
||||
private parseMetadata(metadta: ComponentMetadata) {
|
||||
const { componentName, uri, npm } = metadta;
|
||||
const { componentName, 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,
|
||||
};
|
||||
if (title) {
|
||||
this._title =
|
||||
typeof title === 'string'
|
||||
? {
|
||||
type: 'i18n',
|
||||
'en-US': this.componentName,
|
||||
'zh-CN': title,
|
||||
}
|
||||
: title;
|
||||
}
|
||||
|
||||
const liveTextEditing = this._transformedMetadata.experimental?.liveTextEditing || [];
|
||||
|
||||
function collectLiveTextEditing(items: FieldConfig[]) {
|
||||
items.forEach(config => {
|
||||
if (config.items) {
|
||||
collectLiveTextEditing(config.items);
|
||||
} else {
|
||||
const liveConfig = config.liveTextEditing || config.extraProps?.liveTextEditing;
|
||||
if (liveConfig) {
|
||||
liveTextEditing.push({
|
||||
propTarget: String(config.name),
|
||||
...liveConfig,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
collectLiveTextEditing(this.configure);
|
||||
this._liveTextEditing = liveTextEditing.length > 0 ? liveTextEditing : undefined;
|
||||
|
||||
const { configure = {} } = this._transformedMetadata;
|
||||
this._acceptable = false;
|
||||
|
||||
@ -152,11 +185,11 @@ export class ComponentMeta {
|
||||
this._isContainer = component.isContainer ? true : false;
|
||||
this._isModal = component.isModal ? true : false;
|
||||
this._descriptor = component.descriptor;
|
||||
this._rectSelector = component.rectSelector;
|
||||
this._rootSelector = component.rootSelector;
|
||||
if (component.nestingRule) {
|
||||
const { parentWhitelist, childWhitelist } = component.nestingRule;
|
||||
this.parentWhitelist = ensureAList(parentWhitelist);
|
||||
this.childWhitelist = ensureAList(childWhitelist);
|
||||
this.parentWhitelist = buildFilter(parentWhitelist);
|
||||
this.childWhitelist = buildFilter(childWhitelist);
|
||||
}
|
||||
} else {
|
||||
this._isContainer = false;
|
||||
@ -181,12 +214,14 @@ export class ComponentMeta {
|
||||
|
||||
@computed get availableActions() {
|
||||
let { disableBehaviors, actions } = this._transformedMetadata?.configure.component || {};
|
||||
const disabled = ensureAList(disableBehaviors) || (this.isRootComponent() ? ['copy', 'remove'] : null);
|
||||
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);
|
||||
|
||||
if (disabled) {
|
||||
if (disabled.includes('*')) {
|
||||
return actions.filter((action) => action.condition === 'always');
|
||||
}
|
||||
return actions.filter((action) => disabled.indexOf(action.name) < 0);
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
@ -199,19 +234,28 @@ export class ComponentMeta {
|
||||
return this._transformedMetadata!;
|
||||
}
|
||||
|
||||
checkNestingUp(my: Node | NodeData, parent: NodeParent) {
|
||||
checkNestingUp(my: Node | NodeData, parent: ParentalNode) {
|
||||
// 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器
|
||||
if (this.parentWhitelist) {
|
||||
return this.parentWhitelist.includes(parent.componentName);
|
||||
return this.parentWhitelist(parent, my);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
checkNestingDown(my: Node, target: Node | NodeSchema) {
|
||||
// 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器
|
||||
if (this.childWhitelist) {
|
||||
return this.childWhitelist.includes(target.componentName);
|
||||
return this.childWhitelist(target, my);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// compatiable vision
|
||||
prototype?: any;
|
||||
}
|
||||
|
||||
export function isComponentMeta(obj: any): obj is ComponentMeta {
|
||||
return obj && obj.isComponentMeta;
|
||||
}
|
||||
|
||||
function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMetadata {
|
||||
@ -233,7 +277,39 @@ function preprocessMetadata(metadata: ComponentMetadata): TransformedComponentMe
|
||||
};
|
||||
}
|
||||
|
||||
registerMetadataTransducer(metadata => {
|
||||
|
||||
export interface MetadataTransducer {
|
||||
(prev: TransformedComponentMetadata): TransformedComponentMetadata;
|
||||
/**
|
||||
* 0 - 9 system
|
||||
* 10 - 99 builtin-plugin
|
||||
* 100 - app & plugin
|
||||
*/
|
||||
level?: number;
|
||||
/**
|
||||
* use to replace TODO
|
||||
*/
|
||||
id?: string;
|
||||
}
|
||||
const metadataTransducers: MetadataTransducer[] = [];
|
||||
|
||||
export function registerMetadataTransducer(transducer: MetadataTransducer, level: number = 100, id?: string) {
|
||||
transducer.level = level;
|
||||
transducer.id = id;
|
||||
const i = metadataTransducers.findIndex((item) => item.level != null && item.level > level);
|
||||
if (i < 0) {
|
||||
metadataTransducers.push(transducer);
|
||||
} else {
|
||||
metadataTransducers.splice(i, 0, transducer);
|
||||
}
|
||||
}
|
||||
|
||||
export function getRegisteredMetadataTransducers(): MetadataTransducer[] {
|
||||
return metadataTransducers;
|
||||
}
|
||||
|
||||
|
||||
registerMetadataTransducer((metadata) => {
|
||||
const { configure, componentName } = metadata;
|
||||
const { component = {} } = configure;
|
||||
if (!component.nestingRule) {
|
||||
@ -278,22 +354,48 @@ const builtinComponentActions: ComponentAction[] = [
|
||||
name: 'remove',
|
||||
content: {
|
||||
icon: IconRemove,
|
||||
description: intl('remove'),
|
||||
title: intlNode('remove'),
|
||||
action(node: Node) {
|
||||
node.remove();
|
||||
},
|
||||
},
|
||||
important: true,
|
||||
},
|
||||
{
|
||||
name: 'hide',
|
||||
content: {
|
||||
icon: IconHidden,
|
||||
title: intlNode('hide'),
|
||||
action(node: Node) {
|
||||
node.getExtraProp('hidden', true)?.setValue(true);
|
||||
},
|
||||
},
|
||||
condition: (node: Node) => {
|
||||
return node.componentMeta.isModal;
|
||||
},
|
||||
important: true,
|
||||
},
|
||||
{
|
||||
name: 'copy',
|
||||
content: {
|
||||
icon: IconClone,
|
||||
description: intl('copy'),
|
||||
title: intlNode('copy'),
|
||||
action(node: Node) {
|
||||
// node.remove();
|
||||
const { document: doc, parent, index } = node;
|
||||
parent && doc.insertNode(parent, node, index, true);
|
||||
},
|
||||
},
|
||||
important: true,
|
||||
},
|
||||
];
|
||||
|
||||
export function removeBuiltinComponentAction(name: string) {
|
||||
const i = builtinComponentActions.findIndex((action) => action.name === name);
|
||||
if (i > -1) {
|
||||
builtinComponentActions.splice(i, 1);
|
||||
}
|
||||
}
|
||||
export function addBuiltinComponentAction(action: ComponentAction) {
|
||||
builtinComponentActions.push(action);
|
||||
}
|
||||
|
||||
@ -1,17 +1,38 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { LocationDetail } from './location';
|
||||
import { Node, isNode } from '../document/node/node';
|
||||
import { ComponentInstance } from '../simulator';
|
||||
import { obx } from '@ali/lowcode-editor-core';
|
||||
|
||||
export interface ActiveTarget {
|
||||
node: Node;
|
||||
detail?: LocationDetail;
|
||||
instance?: ComponentInstance;
|
||||
}
|
||||
|
||||
export class ActiveTracker {
|
||||
private emitter = new EventEmitter();
|
||||
|
||||
@obx.ref private _target?: ActiveTarget;
|
||||
|
||||
track(target: ActiveTarget | Node) {
|
||||
this.emitter.emit('change', isNode(target) ? { node: target } : target);
|
||||
if (isNode(target)) {
|
||||
target = { node: target };
|
||||
}
|
||||
this._target = target;
|
||||
this.emitter.emit('change', target);
|
||||
}
|
||||
|
||||
get currentNode() {
|
||||
return this._target?.node;
|
||||
}
|
||||
|
||||
get detail() {
|
||||
return this._target?.detail;
|
||||
}
|
||||
|
||||
get intance() {
|
||||
return this._target?.instance;
|
||||
}
|
||||
|
||||
onChange(fn: (target: ActiveTarget) => void): () => void {
|
||||
|
||||
319
packages/designer/src/designer/builtin-hotkey.ts
Normal file
319
packages/designer/src/designer/builtin-hotkey.ts
Normal file
@ -0,0 +1,319 @@
|
||||
import { hotkey } from '@ali/lowcode-editor-core';
|
||||
import { isFormEvent } from '@ali/lowcode-utils';
|
||||
import { focusing } from './focusing';
|
||||
import { insertChildren, TransformStage } from '../document';
|
||||
import clipboard from './clipboard';
|
||||
|
||||
function getNextForSelect(next: any, head?: any, parent?: any): any {
|
||||
if (next) {
|
||||
if (!head) {
|
||||
return next;
|
||||
}
|
||||
|
||||
let ret;
|
||||
if (next.isContainer()) {
|
||||
const children = next.getChildren() || [];
|
||||
if (children && !children.isEmpty()) {
|
||||
ret = getNextForSelect(children.get(0));
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = getNextForSelect(next.nextSibling);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
return getNextForSelect(parent.nextSibling, false, parent.getParent());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getPrevForSelect(prev: any, head?: any, parent?: any): any {
|
||||
if (prev) {
|
||||
let ret;
|
||||
if (!head && prev.isContainer()) {
|
||||
const children = prev.getChildren() || [];
|
||||
const lastChild = children && !children.isEmpty() ? children.get(children.size - 1) : null;
|
||||
|
||||
ret = getPrevForSelect(lastChild);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!head) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
ret = getPrevForSelect(prev.prevSibling);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// hotkey binding
|
||||
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent) => {
|
||||
// TODO: use focus-tracker
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
const sel = doc.selection;
|
||||
const topItems = sel.getTopNodes();
|
||||
// TODO: check can remove
|
||||
topItems.forEach((node) => {
|
||||
doc.removeNode(node);
|
||||
});
|
||||
sel.clear();
|
||||
});
|
||||
|
||||
hotkey.bind('escape', (e: KeyboardEvent) => {
|
||||
// const currentFocus = focusing.current;
|
||||
const sel = focusing.focusDesigner?.currentDocument?.selection;
|
||||
if (isFormEvent(e) || !sel) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
sel.clear();
|
||||
// currentFocus.esc();
|
||||
});
|
||||
|
||||
// command + c copy command + x cut
|
||||
hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => {
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) return;
|
||||
|
||||
const componentsMap = {};
|
||||
const componentsTree = selected.map((item) => item.export(TransformStage.Clone));
|
||||
|
||||
// FIXME: clear node.id
|
||||
|
||||
const data = { type: 'nodeSchema', componentsMap, componentsTree };
|
||||
|
||||
clipboard.setData(data);
|
||||
|
||||
const cutMode = action && action.indexOf('x') > 0;
|
||||
if (cutMode) {
|
||||
selected.forEach((node) => {
|
||||
const parentNode = node.getParent();
|
||||
parentNode?.select();
|
||||
node.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// command + v paste
|
||||
hotkey.bind(['command+v', 'ctrl+v'], (e) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !designer || !doc) {
|
||||
return;
|
||||
}
|
||||
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
||||
if (componentsTree) {
|
||||
const { target, index } = designer.getSuitableInsertion() || {};
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
const nodes = insertChildren(target, componentsTree, index);
|
||||
if (nodes) {
|
||||
doc.selection.selectAll(nodes.map((o) => o.id));
|
||||
setTimeout(() => designer.activeTracker.track(nodes[0]), 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// command + z undo
|
||||
hotkey.bind(['command+z', 'ctrl+z'], (e) => {
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
his.back();
|
||||
});
|
||||
|
||||
// command + shift + z redo
|
||||
hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e) => {
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
his.forward();
|
||||
});
|
||||
|
||||
// sibling selection
|
||||
hotkey.bind(['left', 'right'], (e, action) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
const firstNode = selected[0];
|
||||
const silbing = action === 'left' ? firstNode?.prevSibling : firstNode?.nextSibling;
|
||||
silbing?.select();
|
||||
});
|
||||
|
||||
hotkey.bind(['up', 'down'], (e, action) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
const firstNode = selected[0];
|
||||
|
||||
if (action === 'down') {
|
||||
const next = getNextForSelect(firstNode, true, firstNode.getParent());
|
||||
next?.select();
|
||||
} else if (action === 'up') {
|
||||
const prev = getPrevForSelect(firstNode, true, firstNode.getParent());
|
||||
prev?.select();
|
||||
}
|
||||
});
|
||||
|
||||
hotkey.bind(['option+left', 'option+right'], (e, action) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||
|
||||
const firstNode = selected[0];
|
||||
const parent = firstNode.getParent();
|
||||
if (!parent) return;
|
||||
|
||||
const isPrev = action && /(left)$/.test(action);
|
||||
|
||||
const silbing = isPrev ? firstNode.prevSibling : firstNode.nextSibling;
|
||||
if (silbing) {
|
||||
if (isPrev) {
|
||||
parent.insertBefore(firstNode, silbing);
|
||||
} else {
|
||||
parent.insertAfter(firstNode, silbing);
|
||||
}
|
||||
firstNode?.select();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
hotkey.bind(['option+up'], (e, action) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||
|
||||
const firstNode = selected[0];
|
||||
const parent = firstNode.getParent();
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const silbing = firstNode.prevSibling;
|
||||
if (silbing) {
|
||||
if (silbing.isContainer()) {
|
||||
const place = silbing.getSuitablePlace(firstNode, null);
|
||||
place.container.insertAfter(firstNode, place.ref);
|
||||
} else {
|
||||
parent.insertBefore(firstNode, silbing);
|
||||
}
|
||||
firstNode?.select();
|
||||
return;
|
||||
} else {
|
||||
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
||||
if (place) {
|
||||
place.container.insertBefore(firstNode, place.ref);
|
||||
firstNode?.select();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
hotkey.bind(['option+down'], (e, action) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) {
|
||||
return;
|
||||
}
|
||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||
|
||||
const firstNode = selected[0];
|
||||
const parent = firstNode.getParent();
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const silbing = firstNode.nextSibling;
|
||||
if (silbing) {
|
||||
if (silbing.isContainer()) {
|
||||
// const place = silbing.getSuitablePlace(firstNode, null);
|
||||
silbing.insertBefore(firstNode, undefined);
|
||||
// place.container.insertBefore(firstNode, place.ref);
|
||||
} else {
|
||||
parent.insertAfter(firstNode, silbing);
|
||||
}
|
||||
firstNode?.select();
|
||||
return;
|
||||
} else {
|
||||
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
||||
if (place) {
|
||||
place.container.insertAfter(firstNode, place.ref);
|
||||
firstNode?.select();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -6,7 +6,17 @@ function getDataFromPasteEvent(event: ClipboardEvent) {
|
||||
|
||||
try {
|
||||
// { componentsMap, componentsTree, ... }
|
||||
return JSON.parse(clipboardData.getData('text/plain'));
|
||||
const data = JSON.parse(clipboardData.getData('text/plain'));
|
||||
if (!data) {
|
||||
return {};
|
||||
}
|
||||
if (data.componentsTree) {
|
||||
return data;
|
||||
} else if (data.componentName) {
|
||||
return {
|
||||
componentsTree: [ data ]
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
/*
|
||||
const html = clipboardData.getData('text/html');
|
||||
@ -19,7 +29,7 @@ function getDataFromPasteEvent(event: ClipboardEvent) {
|
||||
}
|
||||
*/
|
||||
// TODO: open the parser implement
|
||||
return null;
|
||||
return { };
|
||||
/*
|
||||
return {
|
||||
code: clipboardData.getData('text/plain'),
|
||||
@ -64,7 +74,7 @@ class Clipboard {
|
||||
return;
|
||||
}
|
||||
const copyPaster = document.createElement<'textarea'>('textarea');
|
||||
copyPaster.style.cssText = 'position: relative;left: -9999px;';
|
||||
copyPaster.style.cssText = 'position: absolute;left: -9999px;top:-100px';
|
||||
document.body.appendChild(copyPaster);
|
||||
const dispose = this.initCopyPaster(copyPaster);
|
||||
return () => {
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
import { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { TipContainer } from '@ali/lowcode-globals';
|
||||
import BuiltinDragGhostComponent from './drag-ghost';
|
||||
import { Designer, DesignerProps } from './designer';
|
||||
import { ProjectView } from '../project';
|
||||
import './designer.less';
|
||||
import clipboard from './clipboard';
|
||||
|
||||
export class DesignerView extends Component<DesignerProps> {
|
||||
export class DesignerView extends Component<DesignerProps & {
|
||||
designer?: Designer;
|
||||
}> {
|
||||
readonly designer: Designer;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.designer = new Designer(props);
|
||||
const { designer, ...designerProps } = props;
|
||||
if (designer) {
|
||||
this.designer = designer;
|
||||
designer.setProps(designerProps);
|
||||
} else {
|
||||
this.designer = new Designer(designerProps);
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: DesignerProps) {
|
||||
@ -49,7 +56,6 @@ export class DesignerView extends Component<DesignerProps> {
|
||||
<div className={classNames('lc-designer', className)} style={style}>
|
||||
<DragGhost designer={this.designer} />
|
||||
<ProjectView designer={this.designer} />
|
||||
<TipContainer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,48 +1,7 @@
|
||||
@import 'variables.less';
|
||||
|
||||
.lc-designer {
|
||||
--font-family: @font-family;
|
||||
--font-size-label: @fontSize-4;
|
||||
--font-size-text: @fontSize-5;
|
||||
--font-size-btn-large: @fontSize-3;
|
||||
--font-size-btn-medium: @fontSize-4;
|
||||
--font-size-btn-small: @fontSize-5;
|
||||
|
||||
--color-brand: #006cff;
|
||||
--color-brand-light: #197aff;
|
||||
--color-brand-dark: #0060e5;
|
||||
--color-icon: rgba(255, 255, 255, 0.8);
|
||||
--color-visited: rgba(179, 182, 201, 0.4);
|
||||
--color-actived: #498ee6;
|
||||
|
||||
--color-border: @white-alpha-7;
|
||||
--color-btn: #0079F2;
|
||||
--color-btn-border: rgba(0, 121, 242, 0.3);
|
||||
--color-btn-bg: #212938;
|
||||
|
||||
--color-form-bg: #272A35;
|
||||
--color-form-border: rgba(63,70,93,1);
|
||||
|
||||
--color-text: @white-alpha-3;
|
||||
--color-text-light: @white-alpha-1;
|
||||
--color-field-placeholder: @white-alpha-5;
|
||||
--color-pane-label: rgba(255, 255, 255, 0.9);
|
||||
--color-border: rgba(63, 70, 93, 1);
|
||||
--color-field-border: rgba(118, 137, 199, 0.6);
|
||||
--color-function-warning: rgb(204, 131, 98);
|
||||
--color-field-border-hover: rgb(118, 137, 199, 0.8);
|
||||
--color-field-border-active: rgb(118, 137, 199);
|
||||
--color-block-background-disabled: rgba(118, 137, 199, 0.35);
|
||||
|
||||
--global-border-radius: @global-border-radius;
|
||||
--input-border-radius: @input-border-radius;
|
||||
--popup-border-radius: @popup-border-radius;
|
||||
|
||||
position: relative;
|
||||
font-family: var(--font-family);
|
||||
font-size: var(--font-size-text);
|
||||
min-width: 500px;
|
||||
min-height: 500px;
|
||||
box-sizing: border-box;
|
||||
|
||||
* {
|
||||
|
||||
@ -1,27 +1,29 @@
|
||||
import { ComponentType } from 'react';
|
||||
import { EventEmitter } from 'events';
|
||||
import { obx, computed, autorun } from '@ali/lowcode-editor-core';
|
||||
import {
|
||||
ProjectSchema,
|
||||
ComponentMetadata,
|
||||
ComponentAction,
|
||||
NpmInfo,
|
||||
obx,
|
||||
computed,
|
||||
autorun,
|
||||
} from '@ali/lowcode-globals';
|
||||
IEditor,
|
||||
CompositeObject,
|
||||
PropsList,
|
||||
} from '@ali/lowcode-types';
|
||||
import { Project } from '../project';
|
||||
import { Node, DocumentModel, insertChildren, isRootNode, NodeParent } from '../document';
|
||||
import { Node, DocumentModel, insertChildren, isRootNode, ParentalNode, TransformStage } from '../document';
|
||||
import { ComponentMeta } from '../component-meta';
|
||||
import { INodeSelector } from '../simulator';
|
||||
import { INodeSelector, Component } 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 { Detecting } from './detecting';
|
||||
import { DropLocation, LocationData, isLocationChildrenDetail } from './location';
|
||||
import { OffsetObserver, createOffsetObserver } from './offset-observer';
|
||||
import { focusing } from './focusing';
|
||||
import { SettingTopEntry } from './setting';
|
||||
|
||||
export interface DesignerProps {
|
||||
editor: IEditor;
|
||||
className?: string;
|
||||
style?: object;
|
||||
defaultSchema?: ProjectSchema;
|
||||
@ -31,7 +33,6 @@ export interface DesignerProps {
|
||||
dragGhostComponent?: ComponentType<any>;
|
||||
suspensed?: boolean;
|
||||
componentMetadatas?: ComponentMetadata[];
|
||||
eventPipe?: EventEmitter;
|
||||
globalComponentActions?: ComponentAction[];
|
||||
onMount?: (designer: Designer) => void;
|
||||
onDragstart?: (e: LocateEvent) => void;
|
||||
@ -43,8 +44,9 @@ export interface DesignerProps {
|
||||
export class Designer {
|
||||
readonly dragon = new Dragon(this);
|
||||
readonly activeTracker = new ActiveTracker();
|
||||
readonly hovering = new Hovering();
|
||||
readonly detecting = new Detecting();
|
||||
readonly project: Project;
|
||||
readonly editor: IEditor;
|
||||
|
||||
get currentDocument() {
|
||||
return this.project.currentDocument;
|
||||
@ -59,17 +61,32 @@ export class Designer {
|
||||
}
|
||||
|
||||
constructor(props: DesignerProps) {
|
||||
const { editor } = props;
|
||||
this.editor = editor;
|
||||
this.setProps(props);
|
||||
|
||||
this.project = new Project(this, props.defaultSchema);
|
||||
|
||||
let startTime: any;
|
||||
let src = '';
|
||||
this.dragon.onDragstart((e) => {
|
||||
this.hovering.enable = false;
|
||||
startTime = Date.now() / 1000;
|
||||
this.detecting.enable = false;
|
||||
const { dragObject } = e;
|
||||
if (isDragNodeObject(dragObject)) {
|
||||
const node = dragObject.nodes[0]?.parent;
|
||||
const npm = node?.componentMeta?.npm;
|
||||
src =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
node?.componentMeta?.componentName ||
|
||||
'';
|
||||
if (dragObject.nodes.length === 1) {
|
||||
// ensure current selecting
|
||||
dragObject.nodes[0].select();
|
||||
if (dragObject.nodes[0].parent) {
|
||||
// ensure current selecting
|
||||
dragObject.nodes[0].select();
|
||||
} else {
|
||||
this.currentSelection?.clear();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.currentSelection?.clear();
|
||||
@ -91,7 +108,7 @@ export class Designer {
|
||||
const { dragObject, copy } = e;
|
||||
const loc = this._dropLocation;
|
||||
if (loc) {
|
||||
if (isLocationChildrenDetail(loc.detail)) {
|
||||
if (isLocationChildrenDetail(loc.detail) && loc.detail.valid !== false) {
|
||||
let nodes: Node[] | undefined;
|
||||
if (isDragNodeObject(dragObject)) {
|
||||
nodes = insertChildren(loc.target, dragObject.nodes, loc.detail.index, copy);
|
||||
@ -103,15 +120,40 @@ export class Designer {
|
||||
if (nodes) {
|
||||
loc.document.selection.selectAll(nodes.map((o) => o.id));
|
||||
setTimeout(() => this.activeTracker.track(nodes![0]), 10);
|
||||
const endTime: any = Date.now() / 1000;
|
||||
const parent = nodes[0]?.parent;
|
||||
const npm = parent?.componentMeta?.npm;
|
||||
const dest =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
parent?.componentMeta?.componentName ||
|
||||
'';
|
||||
this.editor?.emit('designer.drag', {
|
||||
time: (endTime - startTime).toFixed(2),
|
||||
selected: nodes
|
||||
?.map((n) => {
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
const npm = n?.componentMeta?.npm;
|
||||
return (
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
|
||||
n?.componentMeta?.componentName
|
||||
);
|
||||
})
|
||||
.join('&'),
|
||||
align: loc?.detail?.near?.align || '',
|
||||
pos: loc?.detail?.near?.pos || '',
|
||||
src,
|
||||
dest,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
this.clearLocation();
|
||||
if (this.props?.onDragend) {
|
||||
this.props.onDragend(e, loc);
|
||||
}
|
||||
this.postEvent('dragend', e, loc);
|
||||
this.hovering.enable = true;
|
||||
this.detecting.enable = true;
|
||||
});
|
||||
|
||||
this.activeTracker.onChange(({ node, detail }) => {
|
||||
@ -124,11 +166,11 @@ export class Designer {
|
||||
selectionDispose();
|
||||
selectionDispose = undefined;
|
||||
}
|
||||
this.postEvent('selection-change', this.currentSelection);
|
||||
this.postEvent('selection.change', this.currentSelection);
|
||||
if (this.currentSelection) {
|
||||
const currentSelection = this.currentSelection;
|
||||
selectionDispose = currentSelection.onSelectionChange(() => {
|
||||
this.postEvent('selection-change', currentSelection);
|
||||
this.postEvent('selection.change', currentSelection);
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -138,18 +180,18 @@ export class Designer {
|
||||
historyDispose();
|
||||
historyDispose = undefined;
|
||||
}
|
||||
this.postEvent('history-change', this.currentHistory);
|
||||
this.postEvent('history.change', this.currentHistory);
|
||||
if (this.currentHistory) {
|
||||
const currentHistory = this.currentHistory;
|
||||
historyDispose = currentHistory.onStateChange(() => {
|
||||
this.postEvent('history-change', currentHistory);
|
||||
this.postEvent('history.change', currentHistory);
|
||||
});
|
||||
}
|
||||
};
|
||||
this.project.onCurrentDocumentChange(() => {
|
||||
this.postEvent('current-document-change', this.currentDocument);
|
||||
this.postEvent('selection-change', this.currentSelection);
|
||||
this.postEvent('history-change', this.currentHistory);
|
||||
this.postEvent('current-document.change', this.currentDocument);
|
||||
this.postEvent('selection.change', this.currentSelection);
|
||||
this.postEvent('history.change', this.currentHistory);
|
||||
setupSelection();
|
||||
setupHistory();
|
||||
});
|
||||
@ -162,10 +204,14 @@ export class Designer {
|
||||
}
|
||||
|
||||
postEvent(event: string, ...args: any[]) {
|
||||
this.props?.eventPipe?.emit(`designer.${event}`, ...args);
|
||||
this.editor.emit(`designer.${event}`, ...args);
|
||||
}
|
||||
|
||||
private _dropLocation?: DropLocation;
|
||||
|
||||
get dropLocation() {
|
||||
return this._dropLocation;
|
||||
}
|
||||
/**
|
||||
* 创建插入位置,考虑放到 dragon 中
|
||||
*/
|
||||
@ -194,14 +240,40 @@ export class Designer {
|
||||
return new Scroller(scrollable);
|
||||
}
|
||||
|
||||
private oobxList: OffsetObserver[] = [];
|
||||
createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null {
|
||||
return createOffsetObserver(nodeInstance);
|
||||
const oobx = createOffsetObserver(nodeInstance);
|
||||
this.clearOobxList();
|
||||
if (oobx) {
|
||||
this.oobxList.push(oobx);
|
||||
}
|
||||
return oobx;
|
||||
}
|
||||
|
||||
private clearOobxList(force?: boolean) {
|
||||
let l = this.oobxList.length;
|
||||
if (l > 20 || force) {
|
||||
while (l-- > 0) {
|
||||
if (this.oobxList[l].isPurged()) {
|
||||
this.oobxList.splice(l, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
touchOffsetObserver() {
|
||||
this.clearOobxList(true);
|
||||
this.oobxList.forEach((item) => item.compute());
|
||||
}
|
||||
|
||||
createSettingEntry(nodes: Node[]) {
|
||||
return new SettingTopEntry(this.editor, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得合适的插入位置
|
||||
*/
|
||||
getSuitableInsertion(): { target: NodeParent; index?: number } | null {
|
||||
getSuitableInsertion(): { target: ParentalNode; index?: number } | null {
|
||||
const activedDoc = this.project.currentDocument;
|
||||
if (!activedDoc) {
|
||||
return null;
|
||||
@ -306,24 +378,27 @@ export class Designer {
|
||||
private _lostComponentMetasMap = new Map<string, ComponentMeta>();
|
||||
|
||||
private buildComponentMetasMap(metas: ComponentMetadata[]) {
|
||||
metas.forEach((data) => {
|
||||
const key = data.componentName;
|
||||
let meta = this._componentMetasMap.get(key);
|
||||
metas.forEach((data) => this.createComponentMeta(data));
|
||||
}
|
||||
|
||||
createComponentMeta(data: ComponentMetadata): ComponentMeta {
|
||||
const key = data.componentName;
|
||||
let meta = this._componentMetasMap.get(key);
|
||||
if (meta) {
|
||||
meta.setMetadata(data);
|
||||
} else {
|
||||
meta = this._lostComponentMetasMap.get(key);
|
||||
|
||||
if (meta) {
|
||||
meta.setMetadata(data);
|
||||
this._lostComponentMetasMap.delete(key);
|
||||
} else {
|
||||
meta = this._lostComponentMetasMap.get(key);
|
||||
|
||||
if (meta) {
|
||||
meta.setMetadata(data);
|
||||
this._lostComponentMetasMap.delete(key);
|
||||
} else {
|
||||
meta = new ComponentMeta(this, data);
|
||||
}
|
||||
|
||||
this._componentMetasMap.set(key, meta);
|
||||
meta = new ComponentMeta(this, data);
|
||||
}
|
||||
});
|
||||
|
||||
this._componentMetasMap.set(key, meta);
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
|
||||
getGlobalComponentActions(): ComponentAction[] | null {
|
||||
@ -349,16 +424,56 @@ export class Designer {
|
||||
return meta;
|
||||
}
|
||||
|
||||
@computed get componentsMap(): { [key: string]: NpmInfo } {
|
||||
@computed get componentsMap(): { [key: string]: NpmInfo | Component } {
|
||||
const maps: any = {};
|
||||
this._componentMetasMap.forEach((config, key) => {
|
||||
if (config.npm) {
|
||||
maps[key] = config.npm;
|
||||
const metaData = config.getMetadata();
|
||||
if (metaData.devMode === 'lowcode') {
|
||||
maps[key] = this.currentDocument?.simulator?.createComponent(metaData.schema!);
|
||||
} else {
|
||||
const view = metaData.experimental?.view;
|
||||
if (view) {
|
||||
maps[key] = view;
|
||||
} else if (config.npm) {
|
||||
maps[key] = config.npm;
|
||||
}
|
||||
}
|
||||
});
|
||||
return maps;
|
||||
}
|
||||
|
||||
private propsReducers = new Map<TransformStage, PropsReducer[]>();
|
||||
transformProps(props: CompositeObject | PropsList, node: Node, stage: TransformStage) {
|
||||
if (Array.isArray(props)) {
|
||||
// current not support, make this future
|
||||
return props;
|
||||
}
|
||||
|
||||
const reducers = this.propsReducers.get(stage);
|
||||
if (!reducers) {
|
||||
return props;
|
||||
}
|
||||
|
||||
return reducers.reduce((xprops, reducer) => {
|
||||
try {
|
||||
return reducer(xprops, node)
|
||||
} catch (e) {
|
||||
// todo: add log
|
||||
console.warn(e);
|
||||
return xprops;
|
||||
}
|
||||
}, props);
|
||||
}
|
||||
|
||||
addPropsReducer(reducer: PropsReducer, stage: TransformStage) {
|
||||
const reducers = this.propsReducers.get(stage);
|
||||
if (reducers) {
|
||||
reducers.push(reducer);
|
||||
} else {
|
||||
this.propsReducers.set(stage, [reducer]);
|
||||
}
|
||||
}
|
||||
|
||||
autorun(action: (context: { firstRun: boolean }) => void, sync = false): () => void {
|
||||
return autorun(action, sync as true);
|
||||
}
|
||||
@ -367,3 +482,5 @@ export class Designer {
|
||||
// todo:
|
||||
}
|
||||
}
|
||||
|
||||
export type PropsReducer = (props: CompositeObject, node: Node) => CompositeObject;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { obx } from '@ali/lowcode-globals';
|
||||
import { obx } from '@ali/lowcode-editor-core';
|
||||
import { Node, DocumentModel } from '../document';
|
||||
|
||||
export class Hovering {
|
||||
export class Detecting {
|
||||
@obx.ref private _enable = true;
|
||||
get enable() {
|
||||
return this._enable;
|
||||
@ -19,11 +19,11 @@ export class Hovering {
|
||||
return this._current;
|
||||
}
|
||||
|
||||
hover(node: Node | null) {
|
||||
capture(node: Node | null) {
|
||||
this._current = node;
|
||||
}
|
||||
|
||||
unhover(node: Node) {
|
||||
release(node: Node) {
|
||||
if (this._current === node) {
|
||||
this._current = null;
|
||||
}
|
||||
@ -8,7 +8,7 @@
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0.5;
|
||||
//opacity: 0.9;
|
||||
box-shadow: 0 0 6px grey;
|
||||
transform: translate(-10%, -50%);
|
||||
.lc-ghost {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component } from 'react';
|
||||
import { observer, obx, Title } from '@ali/lowcode-globals';
|
||||
import { observer, obx, Title } from '@ali/lowcode-editor-core';
|
||||
import { Designer } from '../designer';
|
||||
import { DragObject, isDragNodeObject, isDragNodeDataObject } from '../dragon';
|
||||
import './ghost.less';
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { NodeSchema, obx } from '@ali/lowcode-globals';
|
||||
import { obx } from '@ali/lowcode-editor-core';
|
||||
import { NodeSchema } from '@ali/lowcode-types';
|
||||
import { setNativeSelection, cursor } from '@ali/lowcode-utils';
|
||||
import { DropLocation } from './location';
|
||||
import { Node, DocumentModel } from '../document';
|
||||
import { ISimulatorHost, isSimulatorHost } from '../simulator';
|
||||
import { Designer } from './designer';
|
||||
import { setNativeSelection } from '@ali/lowcode-globals';
|
||||
import { cursor } from '@ali/lowcode-globals';
|
||||
|
||||
export interface LocateEvent {
|
||||
readonly type: 'LocateEvent';
|
||||
@ -88,7 +88,6 @@ export interface DragNodeObject {
|
||||
export interface DragNodeDataObject {
|
||||
type: DragObjectType.NodeData;
|
||||
data: NodeSchema | NodeSchema[];
|
||||
maps?: { [componentName: string]: string };
|
||||
thumbnail?: string;
|
||||
description?: string;
|
||||
[extra: string]: any;
|
||||
@ -153,6 +152,9 @@ function getSourceSensor(dragObject: DragObject): ISimulatorHost | null {
|
||||
return dragObject.nodes[0]?.document.simulator || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* make a handler that listen all sensors:document, avoid frame lost
|
||||
*/
|
||||
function makeEventsHandler(
|
||||
boostEvent: MouseEvent | DragEvent,
|
||||
sensors: ISimulatorHost[],
|
||||
@ -160,20 +162,15 @@ function makeEventsHandler(
|
||||
const topDoc = window.top.document;
|
||||
const sourceDoc = boostEvent.view?.document || topDoc;
|
||||
// TODO: optimize this logic, reduce listener
|
||||
// const boostPrevented = boostEvent.defaultPrevented;
|
||||
const docs = new Set<Document>();
|
||||
// if (boostPrevented || isDragEvent(boostEvent)) {
|
||||
docs.add(topDoc);
|
||||
// }
|
||||
docs.add(sourceDoc);
|
||||
// if (sourceDoc !== topDoc || isDragEvent(boostEvent)) {
|
||||
sensors.forEach((sim) => {
|
||||
const sdoc = sim.contentDocument;
|
||||
if (sdoc) {
|
||||
docs.add(sdoc);
|
||||
}
|
||||
});
|
||||
// }
|
||||
|
||||
return (handle: (sdoc: Document) => void) => {
|
||||
docs.forEach((doc) => handle(doc));
|
||||
@ -184,6 +181,9 @@ function isDragEvent(e: any): e is DragEvent {
|
||||
return e?.type?.substr(0, 4) === 'drag';
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag-on 拖拽引擎
|
||||
*/
|
||||
export class Dragon {
|
||||
private sensors: ISensor[] = [];
|
||||
|
||||
@ -201,12 +201,15 @@ export class Dragon {
|
||||
}
|
||||
|
||||
private emitter = new EventEmitter();
|
||||
// private emptyImage: HTMLImageElement = new Image();
|
||||
|
||||
constructor(readonly designer: Designer) {
|
||||
// this.emptyImage.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick listen a shell(container element) drag behavior
|
||||
* @param shell container element
|
||||
* @param boost boost got a drag object
|
||||
*/
|
||||
from(shell: Element, boost: (e: MouseEvent) => DragObject | null) {
|
||||
const mousedown = (e: MouseEvent) => {
|
||||
// ESC or RightClick
|
||||
@ -228,12 +231,18 @@ export class Dragon {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* boost your dragObject for dragging(flying) 发射拖拽对象
|
||||
*
|
||||
* @param dragObject 拖拽对象
|
||||
* @param boostEvent 拖拽初始时事件
|
||||
*/
|
||||
boost(dragObject: DragObject, boostEvent: MouseEvent | DragEvent) {
|
||||
const designer = this.designer;
|
||||
const masterSensors = this.getMasterSensors();
|
||||
const handleEvents = makeEventsHandler(boostEvent, masterSensors);
|
||||
const newBie = !isDragNodeObject(dragObject);
|
||||
const forceCopyState = isDragNodeObject(dragObject) && dragObject.nodes.some((node) => node.isSlotRoot);
|
||||
const forceCopyState = isDragNodeObject(dragObject) && dragObject.nodes.some((node) => node.isSlot());
|
||||
const isBoostFromDragAPI = boostEvent.type.substr(0, 4) === 'drag';
|
||||
let lastSensor: ISensor | undefined;
|
||||
|
||||
@ -319,16 +328,20 @@ export class Dragon {
|
||||
this.emitter.emit('dragstart', locateEvent);
|
||||
};
|
||||
|
||||
// route: drag-move
|
||||
const move = (e: MouseEvent | DragEvent) => {
|
||||
if (isBoostFromDragAPI) {
|
||||
e.preventDefault();
|
||||
}
|
||||
if (this._dragging) {
|
||||
// process dragging
|
||||
drag(e);
|
||||
return;
|
||||
}
|
||||
|
||||
// first move check is shaken
|
||||
if (isShaken(boostEvent, e)) {
|
||||
// is shaken dragstart
|
||||
dragstart();
|
||||
drag(e);
|
||||
}
|
||||
@ -341,6 +354,7 @@ export class Dragon {
|
||||
didDrop = true;
|
||||
};
|
||||
|
||||
// end-tail drag process
|
||||
const over = (e?: any) => {
|
||||
if (e && isDragEvent(e)) {
|
||||
e.preventDefault();
|
||||
@ -366,6 +380,7 @@ export class Dragon {
|
||||
exception = ex;
|
||||
}
|
||||
}
|
||||
designer.clearLocation();
|
||||
|
||||
handleEvents((doc) => {
|
||||
if (isBoostFromDragAPI) {
|
||||
@ -386,6 +401,7 @@ export class Dragon {
|
||||
}
|
||||
};
|
||||
|
||||
// create drag locate event
|
||||
const createLocateEvent = (e: MouseEvent | DragEvent): LocateEvent => {
|
||||
const evt: any = {
|
||||
type: 'LocateEvent',
|
||||
@ -396,12 +412,14 @@ export class Dragon {
|
||||
|
||||
const sourceDocument = e.view?.document;
|
||||
|
||||
// event from current document
|
||||
if (!sourceDocument || sourceDocument === document) {
|
||||
evt.globalX = e.clientX;
|
||||
evt.globalY = e.clientY;
|
||||
} else {
|
||||
} else { // event from simulator sandbox
|
||||
let srcSim: ISimulatorHost | undefined;
|
||||
const lastSim = lastSensor && isSimulatorHost(lastSensor) ? lastSensor : null;
|
||||
// check source simulator
|
||||
if (lastSim && lastSim.contentDocument === sourceDocument) {
|
||||
srcSim = lastSim;
|
||||
} else {
|
||||
@ -411,6 +429,7 @@ export class Dragon {
|
||||
}
|
||||
}
|
||||
if (srcSim) {
|
||||
// transform point by simulator
|
||||
const g = srcSim.viewport.toGlobalPoint(e);
|
||||
evt.globalX = g.clientX;
|
||||
evt.globalY = g.clientY;
|
||||
@ -459,9 +478,7 @@ export class Dragon {
|
||||
const { dataTransfer } = boostEvent;
|
||||
|
||||
if (dataTransfer) {
|
||||
// dataTransfer.setDragImage(this.emptyImage, 0, 0);
|
||||
dataTransfer.effectAllowed = 'all';
|
||||
// dataTransfer.dropEffect = newBie || forceCopyState ? 'copy' : 'move';
|
||||
|
||||
try {
|
||||
dataTransfer.setData('application/json', '{}');
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Designer } from './designer';
|
||||
|
||||
// TODO:
|
||||
// 当前激活区域管理
|
||||
// TODO: use focus-tracker replace
|
||||
class Focusing {
|
||||
focusDesigner?: Designer;
|
||||
}
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
import { Hotkey, isFormEvent } from '@ali/lowcode-globals';
|
||||
import { focusing } from './focusing';
|
||||
import { insertChildren } from '../document';
|
||||
import clipboard from './clipboard';
|
||||
|
||||
export const hotkey = new Hotkey();
|
||||
|
||||
// hotkey binding
|
||||
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent) => {
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
const sel = doc.selection;
|
||||
const topItems = sel.getTopNodes();
|
||||
// TODO: check can remove
|
||||
topItems.forEach(node => {
|
||||
doc.removeNode(node);
|
||||
});
|
||||
sel.clear();
|
||||
});
|
||||
|
||||
hotkey.bind('escape', (e: KeyboardEvent) => {
|
||||
// const currentFocus = focusing.current;
|
||||
const sel = focusing.focusDesigner?.currentDocument?.selection;
|
||||
if (isFormEvent(e) || !sel) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
sel.clear();
|
||||
// currentFocus.esc();
|
||||
});
|
||||
|
||||
// command + c copy command + x cut
|
||||
hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => {
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
/*
|
||||
const doc = getCurrentDocument();
|
||||
if (isFormEvent(e) || !doc || !(focusing.id === 'outline' || focusing.id === 'canvas')) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
*/
|
||||
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) return;
|
||||
|
||||
const componentsMap = {};
|
||||
const componentsTree = selected.map(item => item.export(false));
|
||||
|
||||
const data = { type: 'nodeSchema', componentsMap, componentsTree };
|
||||
|
||||
clipboard.setData(data);
|
||||
/*
|
||||
const cutMode = action.indexOf('x') > 0;
|
||||
if (cutMode) {
|
||||
const parentNode = selected.getParent();
|
||||
parentNode.select();
|
||||
selected.remove();
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
// command + v paste
|
||||
hotkey.bind(['command+v', 'ctrl+v'], (e) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !designer || !doc) {
|
||||
return;
|
||||
}
|
||||
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
||||
if (componentsTree) {
|
||||
const { target, index } = designer.getSuitableInsertion() || {};
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
const nodes = insertChildren(target, componentsTree, index);
|
||||
if (nodes) {
|
||||
doc.selection.selectAll(nodes.map(o => o.id));
|
||||
setTimeout(() => designer.activeTracker.track(nodes[0]), 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// command + z undo
|
||||
hotkey.bind(['command+z', 'ctrl+z'], (e) => {
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
his.back();
|
||||
});
|
||||
|
||||
// command + shift + z redo
|
||||
hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e) => {
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
his.forward();
|
||||
});
|
||||
|
||||
hotkey.mount(window);
|
||||
@ -1,8 +1,9 @@
|
||||
import './builtin-hotkey';
|
||||
export * from './designer';
|
||||
export * from './designer-view';
|
||||
export * from './dragon';
|
||||
export * from './hotkey';
|
||||
export * from './hovering';
|
||||
export * from './detecting';
|
||||
export * from './location';
|
||||
export * from './offset-observer';
|
||||
export * from './scroller';
|
||||
export * from './setting';
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { DocumentModel, Node as ComponentNode, NodeParent } from '../document';
|
||||
import { DocumentModel, Node as ComponentNode, ParentalNode } from '../document';
|
||||
import { LocateEvent } from './dragon';
|
||||
|
||||
export interface LocationData {
|
||||
target: NodeParent; // shadowNode | ConditionFlow | ElementNode | RootNode
|
||||
target: ParentalNode; // shadowNode | ConditionFlow | ElementNode | RootNode
|
||||
detail: LocationDetail;
|
||||
source: string;
|
||||
event: LocateEvent;
|
||||
@ -27,7 +27,7 @@ export interface LocationChildrenDetail {
|
||||
rect?: Rect;
|
||||
align?: 'V' | 'H';
|
||||
};
|
||||
focus?: { type: 'slots' } | { type: 'node'; node: NodeParent };
|
||||
focus?: { type: 'slots' } | { type: 'node'; node: ParentalNode };
|
||||
}
|
||||
|
||||
export interface LocationPropDetail {
|
||||
@ -126,7 +126,7 @@ export function getWindow(elem: Element | Document): Window {
|
||||
}
|
||||
|
||||
export class DropLocation {
|
||||
readonly target: NodeParent;
|
||||
readonly target: ParentalNode;
|
||||
readonly detail: LocationDetail;
|
||||
readonly event: LocateEvent;
|
||||
readonly source: string;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { obx, computed } from '@ali/lowcode-globals';
|
||||
import { uniqueId } from '@ali/lowcode-globals';
|
||||
import { obx, computed } from '@ali/lowcode-editor-core';
|
||||
import { uniqueId } from '@ali/lowcode-utils';
|
||||
import { INodeSelector, IViewport } from '../simulator';
|
||||
import { isRootNode, Node } from '../document';
|
||||
|
||||
@ -82,6 +82,8 @@ export class OffsetObserver {
|
||||
private isRoot: boolean;
|
||||
readonly node: Node;
|
||||
|
||||
readonly compute: () => void;
|
||||
|
||||
constructor(readonly nodeInstance: INodeSelector) {
|
||||
const { node, instance } = nodeInstance;
|
||||
this.node = node;
|
||||
@ -103,7 +105,7 @@ export class OffsetObserver {
|
||||
return;
|
||||
}
|
||||
|
||||
const rect = host.computeComponentInstanceRect(instance!, node.componentMeta.rectSelector);
|
||||
const rect = host.computeComponentInstanceRect(instance!, node.componentMeta.rootSelector);
|
||||
|
||||
if (!rect) {
|
||||
this.hasOffset = false;
|
||||
@ -121,6 +123,8 @@ export class OffsetObserver {
|
||||
this.pid = pid = (window as any).requestIdleCallback(compute);
|
||||
};
|
||||
|
||||
this.compute = compute;
|
||||
|
||||
// try first
|
||||
compute();
|
||||
// try second, ensure the dom mounted
|
||||
@ -133,6 +137,10 @@ export class OffsetObserver {
|
||||
}
|
||||
this.pid = undefined;
|
||||
}
|
||||
|
||||
isPurged() {
|
||||
return this.pid == null;
|
||||
}
|
||||
}
|
||||
|
||||
export function createOffsetObserver(nodeInstance: INodeSelector): OffsetObserver | null {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isElement } from '@ali/lowcode-globals';
|
||||
import { isElement } from '@ali/lowcode-utils';
|
||||
|
||||
export class ScrollTarget {
|
||||
get left() {
|
||||
|
||||
3
packages/designer/src/designer/setting/index.ts
Normal file
3
packages/designer/src/designer/setting/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './setting-field';
|
||||
export * from './setting-top-entry';
|
||||
export * from './setting-entry';
|
||||
17
packages/designer/src/designer/setting/setting-entry.ts
Normal file
17
packages/designer/src/designer/setting/setting-entry.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { SettingTarget } from '@ali/lowcode-types';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { Designer } from '../designer';
|
||||
import { Node } from '../../document';
|
||||
|
||||
export interface SettingEntry extends SettingTarget {
|
||||
readonly nodes: Node[];
|
||||
readonly componentMeta: ComponentMeta | null;
|
||||
readonly designer: Designer;
|
||||
|
||||
// 顶端
|
||||
readonly top: SettingEntry;
|
||||
// 父级
|
||||
readonly parent: SettingEntry;
|
||||
|
||||
get(propName: string | number): SettingEntry;
|
||||
}
|
||||
145
packages/designer/src/designer/setting/setting-field.ts
Normal file
145
packages/designer/src/designer/setting/setting-field.ts
Normal file
@ -0,0 +1,145 @@
|
||||
import { TitleContent, isDynamicSetter, SetterType, DynamicSetter, FieldExtraProps, FieldConfig, CustomView, isCustomView } from '@ali/lowcode-types';
|
||||
import { Transducer } from './utils';
|
||||
import { SettingPropEntry } from './setting-prop-entry';
|
||||
import { SettingEntry } from './setting-entry';
|
||||
import { computed, obx } from '@ali/lowcode-editor-core';
|
||||
import { cloneDeep } from '@ali/lowcode-utils';
|
||||
|
||||
export class SettingField extends SettingPropEntry implements SettingEntry {
|
||||
readonly isSettingField = true;
|
||||
readonly isRequired: boolean;
|
||||
readonly transducer: Transducer;
|
||||
extraProps: FieldExtraProps;
|
||||
|
||||
// ==== dynamic properties ====
|
||||
private _title?: TitleContent;
|
||||
get title() {
|
||||
// FIXME! intl
|
||||
return this._title || (typeof this.name === 'number' ? `项目 ${this.name}` : this.name);
|
||||
}
|
||||
private _setter?: SetterType | DynamicSetter;
|
||||
@computed get setter(): SetterType | null {
|
||||
if (!this._setter) {
|
||||
return null;
|
||||
}
|
||||
if (isDynamicSetter(this._setter)) {
|
||||
return this._setter.call(this,this);
|
||||
}
|
||||
return this._setter;
|
||||
}
|
||||
|
||||
@obx.ref private _expanded = true;
|
||||
get expanded(): boolean {
|
||||
return this._expanded;
|
||||
}
|
||||
|
||||
setExpanded(value: boolean) {
|
||||
this._expanded = value;
|
||||
}
|
||||
|
||||
constructor(readonly parent: SettingEntry, config: FieldConfig, settingFieldCollector?: (name: string | number, field: SettingField) => void) {
|
||||
super(parent, config.name, config.type);
|
||||
|
||||
const { title, items, setter, extraProps, ...rest } = config;
|
||||
this._title = title;
|
||||
this._setter = setter;
|
||||
this.extraProps = {
|
||||
...rest,
|
||||
...extraProps,
|
||||
};
|
||||
this.isRequired = config.isRequired || (setter as any)?.isRequired;
|
||||
this._expanded = extraProps?.defaultCollapsed ? false : true;
|
||||
|
||||
// initial items
|
||||
if (this.type === 'group' && items) {
|
||||
this.initItems(items, settingFieldCollector);
|
||||
} else if (settingFieldCollector && config.name) {
|
||||
settingFieldCollector(config.name, this);
|
||||
}
|
||||
|
||||
// compatiable old config
|
||||
this.transducer = new Transducer(this, { setter });
|
||||
}
|
||||
|
||||
private _items: Array<SettingField | CustomView> = [];
|
||||
|
||||
get items(): Array<SettingField | CustomView> {
|
||||
return this._items;
|
||||
}
|
||||
|
||||
private initItems(items: Array<FieldConfig | CustomView>, settingFieldCollector?: { (name: string | number, field: SettingField): void; (name: string, field: SettingField): void; }) {
|
||||
this._items = items.map((item) => {
|
||||
if (isCustomView(item)) {
|
||||
return item;
|
||||
}
|
||||
return new SettingField(this, item, settingFieldCollector);
|
||||
});
|
||||
}
|
||||
|
||||
private disposeItems() {
|
||||
this._items.forEach(item => isSettingField(item) && item.purge());
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
// 创建子配置项,通常用于 object/array 类型数据
|
||||
createField(config: FieldConfig): SettingField {
|
||||
return new SettingField(this, config);
|
||||
}
|
||||
|
||||
purge() {
|
||||
this.disposeItems();
|
||||
}
|
||||
|
||||
private hotValue: any;
|
||||
|
||||
// ======= compatibles for vision ======
|
||||
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: any) {
|
||||
if (isHotValue) {
|
||||
this.setHotValue(val, extraOptions);
|
||||
return;
|
||||
}
|
||||
super.setValue(val, false, false, extraOptions);
|
||||
}
|
||||
|
||||
getHotValue(): any {
|
||||
if (this.hotValue) {
|
||||
return this.hotValue;
|
||||
}
|
||||
// avoid View modify
|
||||
let v = cloneDeep(this.getMockOrValue());
|
||||
if (v == null) {
|
||||
v = this.extraProps.defaultValue;
|
||||
}
|
||||
return this.transducer.toHot(v);
|
||||
}
|
||||
|
||||
setHotValue(data: any, options?: any) {
|
||||
this.hotValue = data;
|
||||
const v = this.transducer.toNative(data);
|
||||
if (this.isUseVariable()) {
|
||||
const ov = this.getValue();
|
||||
this.setValue({
|
||||
type: 'JSExpression',
|
||||
value: ov.value,
|
||||
mock: v,
|
||||
}, false, false, options);
|
||||
} else {
|
||||
this.setValue(v, false, false, options);
|
||||
}
|
||||
|
||||
// dirty fix list setter
|
||||
if (Array.isArray(data) && data[0] && data[0].__sid__) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.valueChange();
|
||||
}
|
||||
|
||||
onEffect(action: () => void): () => void {
|
||||
return this.designer.autorun(action, true);
|
||||
}
|
||||
}
|
||||
|
||||
export function isSettingField(obj: any): obj is SettingField {
|
||||
return obj && obj.isSettingField;
|
||||
}
|
||||
326
packages/designer/src/designer/setting/setting-prop-entry.ts
Normal file
326
packages/designer/src/designer/setting/setting-prop-entry.ts
Normal file
@ -0,0 +1,326 @@
|
||||
import { obx, computed, autorun } from '@ali/lowcode-editor-core';
|
||||
import { IEditor, isJSExpression } from '@ali/lowcode-types';
|
||||
import { uniqueId } from '@ali/lowcode-utils';
|
||||
import { SettingEntry } from './setting-entry';
|
||||
import { Node } from '../../document';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { Designer } from '../designer';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export class SettingPropEntry implements SettingEntry {
|
||||
// === static properties ===
|
||||
readonly editor: IEditor;
|
||||
readonly isSameComponent: boolean;
|
||||
readonly isMultiple: boolean;
|
||||
readonly isSingle: boolean;
|
||||
readonly nodes: Node[];
|
||||
readonly componentMeta: ComponentMeta | null;
|
||||
readonly designer: Designer;
|
||||
readonly top: SettingEntry;
|
||||
readonly isGroup: boolean;
|
||||
readonly type: 'field' | 'group';
|
||||
readonly id = uniqueId('entry');
|
||||
|
||||
readonly emitter = new EventEmitter();
|
||||
|
||||
// ==== dynamic properties ====
|
||||
@obx.ref private _name: string | number;
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
@computed get path() {
|
||||
const path = this.parent.path.slice();
|
||||
if (this.type === 'field') {
|
||||
path.push(this.name);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
extraProps: any = {};
|
||||
|
||||
constructor(readonly parent: SettingEntry, name: string | number, type?: 'field' | 'group') {
|
||||
if (type == null) {
|
||||
const c = typeof name === 'string' ? name.substr(0, 1) : '';
|
||||
if (c === '#') {
|
||||
this.type = 'group';
|
||||
} else {
|
||||
this.type = 'field';
|
||||
}
|
||||
} else {
|
||||
this.type = type;
|
||||
}
|
||||
// initial self properties
|
||||
this._name = name;
|
||||
this.isGroup = this.type === 'group';
|
||||
|
||||
// copy parent static properties
|
||||
this.editor = parent.editor;
|
||||
this.nodes = parent.nodes;
|
||||
this.componentMeta = parent.componentMeta;
|
||||
this.isSameComponent = parent.isSameComponent;
|
||||
this.isMultiple = parent.isMultiple;
|
||||
this.isSingle = parent.isSingle;
|
||||
this.designer = parent.designer;
|
||||
this.top = parent.top;
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
setKey(key: string | number) {
|
||||
if (this.type !== 'field') {
|
||||
return;
|
||||
}
|
||||
const propName = this.path.join('.');
|
||||
let l = this.nodes.length;
|
||||
while (l-- > 1) {
|
||||
this.nodes[l].getProp(propName, true)!.key = key;
|
||||
}
|
||||
this._name = key;
|
||||
}
|
||||
|
||||
getKey() {
|
||||
return this._name;
|
||||
}
|
||||
|
||||
remove() {
|
||||
if (this.type !== 'field') {
|
||||
return;
|
||||
}
|
||||
const propName = this.path.join('.');
|
||||
let l = this.nodes.length;
|
||||
while (l-- > 1) {
|
||||
this.nodes[l].getProp(propName)?.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// ====== 当前属性读写 =====
|
||||
|
||||
/**
|
||||
* 判断当前属性值是否一致
|
||||
* -1 多种值
|
||||
* 0 无值
|
||||
* 1 类似值,比如数组长度一样
|
||||
* 2 单一植
|
||||
*/
|
||||
@computed get valueState(): number {
|
||||
if (this.type !== 'field') {
|
||||
const { getValue } = this.extraProps;
|
||||
return getValue ? (getValue(this, undefined) === undefined ? 0 : 1) : 0;
|
||||
}
|
||||
const propName = this.path.join('.');
|
||||
const first = this.nodes[0].getProp(propName)!;
|
||||
let l = this.nodes.length;
|
||||
let state = 2;
|
||||
while (l-- > 1) {
|
||||
const next = this.nodes[l].getProp(propName, false);
|
||||
const s = first.compare(next);
|
||||
if (s > 1) {
|
||||
return -1;
|
||||
}
|
||||
if (s === 1) {
|
||||
state = 1;
|
||||
}
|
||||
}
|
||||
if (state === 2 && first.isUnset()) {
|
||||
return 0;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前属性值
|
||||
*/
|
||||
@computed getValue(): any {
|
||||
let val: any = undefined;
|
||||
if (this.type === 'field') {
|
||||
val = this.parent.getPropValue(this.name);
|
||||
}
|
||||
const { getValue } = this.extraProps;
|
||||
try {
|
||||
return getValue ? getValue(this, val) : val;
|
||||
} catch (e) {
|
||||
// todo: add log
|
||||
console.warn(e);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前属性值
|
||||
*/
|
||||
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: any) {
|
||||
if (this.type === 'field') {
|
||||
this.parent.setPropValue(this.name, val);
|
||||
}
|
||||
if (!extraOptions) {
|
||||
extraOptions = {};
|
||||
}
|
||||
const { setValue } = this.extraProps;
|
||||
if (setValue && !extraOptions.disableMutator) {
|
||||
try {
|
||||
setValue(this, val);
|
||||
} catch (e) {
|
||||
// todo: add log
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除已设置的值
|
||||
*/
|
||||
clearValue() {
|
||||
if (this.type === 'field') {
|
||||
this.parent.clearPropValue(this.name);
|
||||
}
|
||||
const { setValue } = this.extraProps;
|
||||
if (setValue) {
|
||||
try {
|
||||
setValue(this, undefined);
|
||||
} catch (e) {
|
||||
// todo: add log
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子项
|
||||
*/
|
||||
get(propName: string | number) {
|
||||
const path = this.path.concat(propName).join('.');
|
||||
return this.top.get(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置子级属性值
|
||||
*/
|
||||
setPropValue(propName: string | number, value: any) {
|
||||
const path = this.path.concat(propName).join('.');
|
||||
this.top.setPropValue(path, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除已设置值
|
||||
*/
|
||||
clearPropValue(propName: string | number) {
|
||||
const path = this.path.concat(propName).join('.');
|
||||
this.top.clearPropValue(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子级属性值
|
||||
*/
|
||||
getPropValue(propName: string | number): any {
|
||||
return this.top.getPropValue(this.path.concat(propName).join('.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶层附属属性值
|
||||
*/
|
||||
getExtraPropValue(propName: string) {
|
||||
return this.top.getExtraPropValue(propName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置顶层附属属性值
|
||||
*/
|
||||
setExtraPropValue(propName: string, value: any) {
|
||||
this.top.setExtraPropValue(propName, value);
|
||||
}
|
||||
|
||||
// ======= compatibles for vision ======
|
||||
getNode() {
|
||||
return this.nodes[0];
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.path.join('.');
|
||||
}
|
||||
|
||||
getProps() {
|
||||
return this.top;
|
||||
}
|
||||
|
||||
// add settingfield props
|
||||
get props() {
|
||||
return this.top;
|
||||
}
|
||||
|
||||
onValueChange(func: () => any) {
|
||||
this.emitter.on('valuechange', func);
|
||||
|
||||
return () => {
|
||||
this.emitter.removeListener('valuechange', func);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
valueChange() {
|
||||
this.emitter.emit('valuechange');
|
||||
}
|
||||
|
||||
getDefaultValue() {
|
||||
return this.extraProps.defaultValue;
|
||||
}
|
||||
|
||||
isIgnore() {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
getConfig<K extends keyof IPropConfig>(configName?: K): IPropConfig[K] | IPropConfig {
|
||||
if (configName) {
|
||||
return this.config[configName];
|
||||
}
|
||||
|
||||
return this.config;
|
||||
}
|
||||
*/
|
||||
getVariableValue() {
|
||||
const v = this.getValue();
|
||||
if (isJSExpression(v)) {
|
||||
return v.value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
setVariableValue(value: string) {
|
||||
const v = this.getValue();
|
||||
this.setValue({
|
||||
type: 'JSExpression',
|
||||
value,
|
||||
mock: isJSExpression(v) ? v.mock : v,
|
||||
});
|
||||
}
|
||||
setUseVariable(flag: boolean) {
|
||||
if (this.isUseVariable() === flag) {
|
||||
return;
|
||||
}
|
||||
const v = this.getValue();
|
||||
if (isJSExpression(v)) {
|
||||
this.setValue(v.mock);
|
||||
} else {
|
||||
this.setValue({
|
||||
type: 'JSExpression',
|
||||
value: '',
|
||||
mock: v,
|
||||
});
|
||||
}
|
||||
}
|
||||
isUseVariable() {
|
||||
return isJSExpression(this.getValue());
|
||||
}
|
||||
get useVariable() {
|
||||
return this.isUseVariable();
|
||||
}
|
||||
getMockOrValue() {
|
||||
const v = this.getValue();
|
||||
if (isJSExpression(v)) {
|
||||
return v.mock;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
234
packages/designer/src/designer/setting/setting-top-entry.ts
Normal file
234
packages/designer/src/designer/setting/setting-top-entry.ts
Normal file
@ -0,0 +1,234 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { CustomView, isCustomView, IEditor } from '@ali/lowcode-types';
|
||||
import { computed } from '@ali/lowcode-editor-core';
|
||||
import { SettingEntry } from './setting-entry';
|
||||
import { SettingField, isSettingField } from './setting-field';
|
||||
import { SettingPropEntry } from './setting-prop-entry';
|
||||
import { Node } from '../../document';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { Designer } from '../designer';
|
||||
|
||||
function generateSessionId(nodes: Node[]) {
|
||||
return nodes
|
||||
.map((node) => node.id)
|
||||
.sort()
|
||||
.join(',');
|
||||
}
|
||||
|
||||
export class SettingTopEntry implements SettingEntry {
|
||||
private emitter = new EventEmitter();
|
||||
private _items: Array<SettingField | CustomView> = [];
|
||||
private _componentMeta: ComponentMeta | null = null;
|
||||
private _isSame: boolean = true;
|
||||
private _settingFieldMap: { [prop: string]: SettingField } = {};
|
||||
readonly path = [];
|
||||
readonly top = this;
|
||||
readonly parent = this;
|
||||
|
||||
get componentMeta() {
|
||||
return this._componentMeta;
|
||||
}
|
||||
|
||||
get items() {
|
||||
return this._items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同样的
|
||||
*/
|
||||
get isSameComponent(): boolean {
|
||||
return this._isSame;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一个
|
||||
*/
|
||||
get isSingle(): boolean {
|
||||
return this.nodes.length === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多个
|
||||
*/
|
||||
get isMultiple(): boolean {
|
||||
return this.nodes.length > 1;
|
||||
}
|
||||
|
||||
readonly id: string;
|
||||
readonly first: Node;
|
||||
readonly designer: Designer;
|
||||
|
||||
constructor(readonly editor: IEditor, readonly nodes: Node[]) {
|
||||
if (nodes.length < 1) {
|
||||
throw new ReferenceError('nodes should not be empty');
|
||||
}
|
||||
this.id = generateSessionId(nodes);
|
||||
this.first = nodes[0];
|
||||
this.designer = this.first.document.designer;
|
||||
|
||||
// setups
|
||||
this.setupComponentMeta();
|
||||
|
||||
// clear fields
|
||||
this.setupItems();
|
||||
}
|
||||
|
||||
private setupComponentMeta() {
|
||||
// todo: enhance compile a temp configure.compiled
|
||||
const first = this.first;
|
||||
const meta = first.componentMeta;
|
||||
const l = this.nodes.length;
|
||||
let theSame = true;
|
||||
for (let i = 1; i < l; i++) {
|
||||
const other = this.nodes[i];
|
||||
if (other.componentMeta !== meta) {
|
||||
theSame = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (theSame) {
|
||||
this._isSame = true;
|
||||
this._componentMeta = meta;
|
||||
} else {
|
||||
this._isSame = false;
|
||||
this._componentMeta = null;
|
||||
}
|
||||
}
|
||||
|
||||
private setupItems() {
|
||||
if (this.componentMeta) {
|
||||
const settingFieldMap: { [prop: string]: SettingField } = {};
|
||||
const settingFieldCollector = (name: string | number, field: SettingField) => {
|
||||
settingFieldMap[name] = field;
|
||||
}
|
||||
this._items = this.componentMeta.configure.map((item) => {
|
||||
if (isCustomView(item)) {
|
||||
return item;
|
||||
}
|
||||
return new SettingField(this, item as any, settingFieldCollector);
|
||||
});
|
||||
this._settingFieldMap = settingFieldMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前属性值
|
||||
*/
|
||||
@computed getValue(): any {
|
||||
this.first.propsData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前属性值
|
||||
*/
|
||||
setValue(val: any) {
|
||||
this.setProps(val);
|
||||
// TODO: emit value change
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子项
|
||||
*/
|
||||
get(propName: string | number): SettingPropEntry {
|
||||
return this._settingFieldMap[propName] || (new SettingPropEntry(this, propName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置子级属性值
|
||||
*/
|
||||
setPropValue(propName: string, value: any) {
|
||||
this.nodes.forEach((node) => {
|
||||
node.setPropValue(propName, value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除已设置值
|
||||
*/
|
||||
clearPropValue(propName: string) {
|
||||
this.nodes.forEach((node) => {
|
||||
node.clearPropValue(propName);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子级属性值
|
||||
*/
|
||||
getPropValue(propName: string): any {
|
||||
return this.first.getProp(propName, true)?.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶层附属属性值
|
||||
*/
|
||||
getExtraPropValue(propName: string) {
|
||||
return this.first.getExtraProp(propName, false)?.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置顶层附属属性值
|
||||
*/
|
||||
setExtraPropValue(propName: string, value: any) {
|
||||
this.nodes.forEach((node) => {
|
||||
node.getExtraProp(propName, true)?.setValue(value);
|
||||
});
|
||||
}
|
||||
|
||||
// 设置多个属性值,替换原有值
|
||||
setProps(data: object) {
|
||||
this.nodes.forEach((node) => {
|
||||
node.setProps(data as any);
|
||||
});
|
||||
}
|
||||
|
||||
// 设置多个属性值,和原有值合并
|
||||
mergeProps(data: object) {
|
||||
this.nodes.forEach((node) => {
|
||||
node.mergeProps(data as any);
|
||||
});
|
||||
}
|
||||
|
||||
private disposeItems() {
|
||||
this._items.forEach((item) => isPurgeable(item) && item.purge());
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
purge() {
|
||||
this.disposeItems();
|
||||
this.emitter.removeAllListeners();
|
||||
}
|
||||
|
||||
|
||||
// ==== compatibles for vision =====
|
||||
getProp(propName: string | number) {
|
||||
return this.get(propName);
|
||||
}
|
||||
|
||||
// ==== copy some Node api =====
|
||||
// `VE.Node.getProps`
|
||||
getStatus() {
|
||||
|
||||
}
|
||||
setStatus() {
|
||||
|
||||
}
|
||||
getChildren() {
|
||||
// this.nodes.map()
|
||||
}
|
||||
getDOMNode() {
|
||||
|
||||
}
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
getPage() {
|
||||
return this.first.document;
|
||||
}
|
||||
}
|
||||
|
||||
interface Purgeable {
|
||||
purge(): void;
|
||||
}
|
||||
function isPurgeable(obj: any): obj is Purgeable {
|
||||
return obj && obj.purge;
|
||||
}
|
||||
67
packages/designer/src/designer/setting/utils.js
Normal file
67
packages/designer/src/designer/setting/utils.js
Normal file
@ -0,0 +1,67 @@
|
||||
// all this file for polyfill vision logic
|
||||
|
||||
import { isValidElement } from 'react';
|
||||
import { isSetterConfig } from '@ali/lowcode-types';
|
||||
import { getSetter } from '@ali/lowcode-editor-core';
|
||||
|
||||
function getHotterFromSetter(setter) {
|
||||
return setter && (setter.Hotter || (setter.type && setter.type.Hotter)) || []; // eslint-disable-line
|
||||
}
|
||||
|
||||
function getTransducerFromSetter(setter) {
|
||||
return setter && (
|
||||
setter.transducer || setter.Transducer
|
||||
|| (setter.type && (setter.type.transducer || setter.type.Transducer))
|
||||
) || null; // eslint-disable-line
|
||||
}
|
||||
|
||||
function combineTransducer(transducer, arr, context) {
|
||||
if (!transducer && Array.isArray(arr)) {
|
||||
const [toHot, toNative] = arr;
|
||||
transducer = { toHot, toNative };
|
||||
}
|
||||
|
||||
return {
|
||||
toHot: (transducer && transducer.toHot || (x => x)).bind(context), // eslint-disable-line
|
||||
toNative: (transducer && transducer.toNative || (x => x)).bind(context), // eslint-disable-line
|
||||
};
|
||||
}
|
||||
|
||||
export class Transducer {
|
||||
constructor(context, config) {
|
||||
let { setter } = config;
|
||||
|
||||
// 1. validElement
|
||||
// 2. SetterConfig
|
||||
// 3. SetterConfig[]
|
||||
if (Array.isArray(setter)) {
|
||||
setter = setter[0];
|
||||
} else if (isValidElement(setter) && setter.type.displayName === 'MixedSetter') {
|
||||
setter = setter.props.setters[0];
|
||||
} else if (typeof setter === 'object' && setter.componentName === 'MixedSetter') {
|
||||
setter = setter.props.setters?.[0];
|
||||
}
|
||||
|
||||
if (isSetterConfig(setter)) {
|
||||
setter = setter.componentName;
|
||||
}
|
||||
if (typeof setter === 'string') {
|
||||
setter = getSetter(setter)?.component;
|
||||
}
|
||||
|
||||
this.setterTransducer = combineTransducer(
|
||||
getTransducerFromSetter(setter),
|
||||
getHotterFromSetter(setter),
|
||||
context,
|
||||
);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
toHot(data) {
|
||||
return this.setterTransducer.toHot(data);
|
||||
}
|
||||
|
||||
toNative(data) {
|
||||
return this.setterTransducer.toNative(data);
|
||||
}
|
||||
}
|
||||
@ -1,170 +0,0 @@
|
||||
/*
|
||||
* 基础的 DPL 定义使用了 kuma base 的定义,参考:
|
||||
* https://github.com/uxcore/kuma-base/tree/master/variables
|
||||
*/
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ==================== Font Family ==========================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* @font-family: "STHeiti", "Microsoft Yahei", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif;
|
||||
*/
|
||||
|
||||
@font-family: 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial, sans-serif;
|
||||
@font-family-code: Monaco, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Helvetica, Arial, sans-serif;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ===================== Color DPL ===========================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@brand-color-1: rgba(0, 108, 255, 1);
|
||||
@brand-color-2: rgba(25, 122, 255, 1);
|
||||
@brand-color-3: rgba(0, 96, 229, 1);
|
||||
|
||||
@brand-color-1-3: rgba(0, 108, 255, 0.6);
|
||||
@brand-color-1-4: rgba(0, 108, 255, 0.4);
|
||||
@brand-color-1-5: rgba(0, 108, 255, 0.3);
|
||||
@brand-color-1-6: rgba(0, 108, 255, 0.2);
|
||||
@brand-color-1-7: rgba(0, 108, 255, 0.1);
|
||||
|
||||
@brand-color: @brand-color-1;
|
||||
|
||||
@white-alpha-1: rgb(255, 255, 255); // W-1
|
||||
@white-alpha-2: rgba(255, 255, 255, 0.8); // W-2 A80
|
||||
@white-alpha-3: rgba(255, 255, 255, 0.6); // W-3 A60
|
||||
@white-alpha-4: rgba(255, 255, 255, 0.4); // W-4 A40
|
||||
@white-alpha-5: rgba(255, 255, 255, 0.3); // W-5 A30
|
||||
@white-alpha-6: rgba(255, 255, 255, 0.2); // W-6 A20
|
||||
@white-alpha-7: rgba(255, 255, 255, 0.1); // W-7 A10
|
||||
@white-alpha-8: rgba(255, 255, 255, 0.06); // W-8 A6
|
||||
|
||||
@dark-alpha-1: rgba(0, 0, 0, 1); // D-1 A100
|
||||
@dark-alpha-2: rgba(0, 0, 0, 0.8); // D-2 A80
|
||||
@dark-alpha-3: rgba(0, 0, 0, 0.6); // D-3 A60
|
||||
@dark-alpha-4: rgba(0, 0, 0, 0.4); // D-4 A40
|
||||
@dark-alpha-5: rgba(0, 0, 0, 0.3); // D-5 A30
|
||||
@dark-alpha-6: rgba(0, 0, 0, 0.2); // D-6 A20
|
||||
@dark-alpha-7: rgba(0, 0, 0, 0.1); // D-7 A10
|
||||
@dark-alpha-8: rgba(0, 0, 0, 0.06); // D-8 A6
|
||||
@dark-alpha-9: rgba(0, 0, 0, 0.04); // D-9 A4
|
||||
|
||||
@normal-alpha-1: rgba(31, 56, 88, 1); // N-1 A100
|
||||
@normal-alpha-2: rgba(31, 56, 88, 0.8); // N-2 A80
|
||||
@normal-alpha-3: rgba(31, 56, 88, 0.6); // N-3 A60
|
||||
@normal-alpha-4: rgba(31, 56, 88, 0.4); // N-4 A40
|
||||
@normal-alpha-5: rgba(31, 56, 88, 0.3); // N-5 A30
|
||||
@normal-alpha-6: rgba(31, 56, 88, 0.2); // N-6 A20
|
||||
@normal-alpha-7: rgba(31, 56, 88, 0.1); // N-7 A10
|
||||
@normal-alpha-8: rgba(31, 56, 88, 0.06); // N-8 A6
|
||||
@normal-alpha-9: rgba(31, 56, 88, 0.04); // N-9 A4
|
||||
|
||||
@normal-3: #77879c;
|
||||
@normal-4: #a3aebd;
|
||||
@normal-5: #bac3cc;
|
||||
@normal-6: #d1d7de;
|
||||
|
||||
@gray-dark: #333; // N2_4
|
||||
@gray: #666; // N2_3
|
||||
@gray-light: #999; // N2_2
|
||||
@gray-lighter: #ccc; // N2_1
|
||||
|
||||
@brand-secondary: #2c2f33; // B2_3
|
||||
// 补色
|
||||
@brand-complement: #00b3e8; // B3_1
|
||||
// 复合
|
||||
@brand-comosite: #00c587; // B3_2
|
||||
// 浓度
|
||||
@brand-deep: #73461d; // B3_3
|
||||
|
||||
// F1-1
|
||||
@brand-danger: rgb(240, 70, 49);
|
||||
// F1-2 (10% white)
|
||||
@brand-danger-hover: rgba(240, 70, 49, 0.9);
|
||||
// F1-3 (5% black)
|
||||
@brand-danger-focus: rgba(240, 70, 49, 0.95);
|
||||
|
||||
// F2-1
|
||||
@brand-warning: rgb(250, 189, 14);
|
||||
// F3-1
|
||||
@brand-success: rgb(102, 188, 92);
|
||||
// F4-1
|
||||
@brand-link: rgb(102, 188, 92);
|
||||
// F4-2
|
||||
@brand-link-hover: #2e76a6;
|
||||
|
||||
// F1-1-7 A10
|
||||
@brand-danger-alpha-7: rgba(240, 70, 49, 0.9);
|
||||
// F1-1-8 A6
|
||||
@brand-danger-alpha-8: rgba(240, 70, 49, 0.8);
|
||||
// F2-1-2 A80
|
||||
@brand-warning-alpha-2: rgba(250, 189, 14, 0.8);
|
||||
// F2-1-7 A10
|
||||
@brand-warning-alpha-7: rgba(250, 189, 14, 0.9);
|
||||
// F3-1-2 A80
|
||||
@brand-success-alpha-2: rgba(102, 188, 92, 0.8);
|
||||
// F3-1-7 A10
|
||||
@brand-success-alpha-7: rgba(102, 188, 92, 0.9);
|
||||
// F4-1-7 A10
|
||||
@brand-link-alpha-7: rgba(102, 188, 92, 0.9);
|
||||
|
||||
// 文本色
|
||||
@text-primary-color: @dark-alpha-3;
|
||||
@text-secondary-color: @normal-alpha-3;
|
||||
@text-thirdary-color: @dark-alpha-4;
|
||||
@text-disabled-color: @normal-alpha-5;
|
||||
@text-helper-color: @dark-alpha-4;
|
||||
@text-danger-color: @brand-danger;
|
||||
@text-ali-color: #ec6c00;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* =================== Shadow Box ============================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@box-shadow-1: 0 1px 4px 0 rgba(31, 56, 88, 0.15); // 1 级阴影,物体由原来存在于底面的物体展开,物体和底面关联紧密
|
||||
@box-shadow-2: 0 2px 10px 0 rgba(31, 56, 88, 0.15); // 2 级阴影,hover状态,物体层级较高
|
||||
@box-shadow-3: 0 4px 15px 0 rgba(31, 56, 88, 0.15); // 3 级阴影,当物体层级高于所有界面元素,弹窗用
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ================= FontSize of Level =======================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@fontSize-1: 26px;
|
||||
@fontSize-2: 20px;
|
||||
@fontSize-3: 16px;
|
||||
@fontSize-4: 14px;
|
||||
@fontSize-5: 12px;
|
||||
|
||||
@fontLineHeight-1: 38px;
|
||||
@fontLineHeight-2: 30px;
|
||||
@fontLineHeight-3: 26px;
|
||||
@fontLineHeight-4: 24px;
|
||||
@fontLineHeight-5: 20px;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ================= FontSize of Level =======================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@global-border-radius: 3px;
|
||||
@input-border-radius: 3px;
|
||||
@popup-border-radius: 6px;
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* ===================== Transistion =========================
|
||||
* ===========================================================
|
||||
*/
|
||||
|
||||
@transition-duration: 0.3s;
|
||||
@transition-ease: cubic-bezier(0.23, 1, 0.32, 1);
|
||||
@transition-delay: 0s;
|
||||
@ -1,24 +1,24 @@
|
||||
import {
|
||||
RootSchema,
|
||||
NodeData,
|
||||
isJSExpression,
|
||||
isDOMText,
|
||||
NodeSchema,
|
||||
computed,
|
||||
obx,
|
||||
autorun,
|
||||
isNodeSchema,
|
||||
uniqueId,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { computed, obx } from '@ali/lowcode-editor-core';
|
||||
import { NodeData, isJSExpression, isDOMText, NodeSchema, isNodeSchema, RootSchema } from '@ali/lowcode-types';
|
||||
import { EventEmitter } from 'events';
|
||||
import { Project } from '../project';
|
||||
import { ISimulatorHost } from '../simulator';
|
||||
import { ComponentMeta } from '../component-meta';
|
||||
import { isDragNodeDataObject, DragNodeObject, DragNodeDataObject, DropLocation } from '../designer';
|
||||
import { Node, isNodeParent, insertChildren, insertChild, NodeParent, isNode } from './node/node';
|
||||
import { Node, insertChildren, insertChild, isNode, RootNode, ParentalNode } from './node/node';
|
||||
import { Selection } from './selection';
|
||||
import { RootNode } from './node/root-node';
|
||||
import { History } from './history';
|
||||
import { Prop } from './node/props/prop';
|
||||
import { TransformStage } from './node';
|
||||
import { uniqueId } from '@ali/lowcode-utils';
|
||||
import ModalNodesManager from './node/modalNodesManager';
|
||||
|
||||
export type GetDataType<T, NodeType> = T extends undefined
|
||||
? NodeType extends {
|
||||
schema: infer R;
|
||||
}
|
||||
? R
|
||||
: any
|
||||
: T;
|
||||
|
||||
export class DocumentModel {
|
||||
/**
|
||||
@ -28,7 +28,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 文档编号
|
||||
*/
|
||||
readonly id: string = uniqueId('doc');
|
||||
id: string = uniqueId('doc');
|
||||
/**
|
||||
* 选区控制
|
||||
*/
|
||||
@ -42,6 +42,9 @@ export class DocumentModel {
|
||||
@obx.val private nodes = new Set<Node>();
|
||||
private seqId = 0;
|
||||
private _simulator?: ISimulatorHost;
|
||||
private emitter: EventEmitter;
|
||||
private rootNodeVisitorMap: { [visitorName: string]: any } = {};
|
||||
private modalNodesManager: ModalNodesManager;
|
||||
|
||||
/**
|
||||
* 模拟器
|
||||
@ -58,7 +61,7 @@ export class DocumentModel {
|
||||
this.rootNode.getExtraProp('fileName', true)?.setValue(fileName);
|
||||
}
|
||||
|
||||
private _modalNode?: NodeParent;
|
||||
private _modalNode?: ParentalNode;
|
||||
private _blank?: boolean;
|
||||
get modalNode() {
|
||||
return this._modalNode;
|
||||
@ -68,29 +71,47 @@ export class DocumentModel {
|
||||
return this.modalNode || this.rootNode;
|
||||
}
|
||||
|
||||
private inited = false;
|
||||
constructor(readonly project: Project, schema?: RootSchema) {
|
||||
/*
|
||||
// TODO
|
||||
// use special purge process
|
||||
autorun(() => {
|
||||
this.nodes.forEach((item) => {
|
||||
if (item.parent == null && item !== this.rootNode) {
|
||||
item.purge();
|
||||
}
|
||||
});
|
||||
console.info(this.willPurgeSpace);
|
||||
}, true);
|
||||
*/
|
||||
this.emitter = new EventEmitter();
|
||||
|
||||
if (!schema) {
|
||||
this._blank = true;
|
||||
}
|
||||
|
||||
this.rootNode = this.createRootNode(schema || {
|
||||
componentName: 'Page',
|
||||
fileName: ''
|
||||
});
|
||||
this.rootNode = this.createNode<RootNode>(
|
||||
schema || {
|
||||
componentName: 'Page',
|
||||
id: 'root',
|
||||
fileName: '',
|
||||
},
|
||||
);
|
||||
|
||||
this.history = new History(
|
||||
() => this.schema,
|
||||
() => this.export(TransformStage.Serilize),
|
||||
(schema) => this.import(schema as RootSchema, true),
|
||||
);
|
||||
this.setupListenActiveNodes();
|
||||
this.modalNodesManager = new ModalNodesManager(this);
|
||||
this.inited = true;
|
||||
}
|
||||
|
||||
@obx.val private willPurgeSpace: Node[] = [];
|
||||
addWillPurge(node: Node) {
|
||||
this.willPurgeSpace.push(node);
|
||||
}
|
||||
removeWillPurge(node: Node) {
|
||||
const i = this.willPurgeSpace.indexOf(node);
|
||||
if (i > -1) {
|
||||
this.willPurgeSpace.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@computed isBlank() {
|
||||
@ -98,12 +119,19 @@ export class DocumentModel {
|
||||
}
|
||||
|
||||
readonly designer = this.project.designer;
|
||||
// getAddonData(name: string) {
|
||||
// const addon = this.addons.find((item) => item.name === name);
|
||||
// if (addon) {
|
||||
// return addon.exportData();
|
||||
// }
|
||||
// return this.addonsData[name];
|
||||
// }
|
||||
|
||||
/**
|
||||
* 生成唯一id
|
||||
*/
|
||||
nextId() {
|
||||
return (++this.seqId).toString(36).toLocaleLowerCase();
|
||||
return this.id + (++this.seqId).toString(36).toLocaleLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +158,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 根据 schema 创建一个节点
|
||||
*/
|
||||
createNode(data: NodeData, slotFor?: Prop): Node {
|
||||
createNode<T extends Node = Node, C = undefined>(data: GetDataType<C, T>): T {
|
||||
let schema: any;
|
||||
if (isDOMText(data) || isJSExpression(data)) {
|
||||
schema = {
|
||||
@ -142,6 +170,9 @@ export class DocumentModel {
|
||||
}
|
||||
|
||||
let node: Node | null = null;
|
||||
if (!this.inited) {
|
||||
schema.id = null;
|
||||
}
|
||||
if (schema.id) {
|
||||
node = this.getNode(schema.id);
|
||||
if (node && node.componentName === schema.componentName) {
|
||||
@ -150,46 +181,45 @@ export class DocumentModel {
|
||||
// will move to another position
|
||||
// todo: this.activeNodes?.push(node);
|
||||
}
|
||||
node.internalSetSlotFor(slotFor);
|
||||
node.import(schema, true);
|
||||
} else if (node) {
|
||||
node = null;
|
||||
}
|
||||
}
|
||||
if (!node) {
|
||||
node = new Node(this, schema, slotFor);
|
||||
node = new Node(this, schema);
|
||||
// will add
|
||||
// todo: this.activeNodes?.push(node);
|
||||
}
|
||||
|
||||
if (this.nodesMap.has(node.id)) {
|
||||
this.nodesMap.get(node.id)!.internalSetParent(null);
|
||||
const origin = this.nodesMap.get(node.id);
|
||||
if (origin && origin !== node) {
|
||||
// almost will not go here, ensure the id is unique
|
||||
origin.internalSetWillPurge();
|
||||
}
|
||||
|
||||
this.nodesMap.set(node.id, node);
|
||||
this.nodes.add(node);
|
||||
|
||||
return node;
|
||||
this.emitter.emit('nodecreate', node);
|
||||
return node as any;
|
||||
}
|
||||
|
||||
private createRootNode(schema: RootSchema) {
|
||||
const node = new RootNode(this, schema);
|
||||
this.nodesMap.set(node.id, node);
|
||||
this.nodes.add(node);
|
||||
return node;
|
||||
public destroyNode(node: Node) {
|
||||
this.emitter.emit('nodedestroy', node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入一个节点
|
||||
*/
|
||||
insertNode(parent: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
insertNode(parent: ParentalNode, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
return insertChild(parent, thing, at, copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入多个节点
|
||||
*/
|
||||
insertNodes(parent: NodeParent, thing: Node[] | NodeData[], at?: number | null, copy?: boolean) {
|
||||
insertNodes(parent: ParentalNode, thing: Node[] | NodeData[], at?: number | null, copy?: boolean) {
|
||||
return insertChildren(parent, thing, at, copy);
|
||||
}
|
||||
|
||||
@ -224,6 +254,14 @@ export class DocumentModel {
|
||||
this.selection.remove(node.id);
|
||||
node.remove();
|
||||
}
|
||||
getAddonData(name: string) {
|
||||
const addon = this.getNode(name);
|
||||
if (addon) {
|
||||
// 无法确定是否有这个api
|
||||
// return addon.exportData();
|
||||
}
|
||||
return addon;
|
||||
}
|
||||
|
||||
@obx.ref private _dropLocation: DropLocation | null = null;
|
||||
/**
|
||||
@ -249,7 +287,7 @@ export class DocumentModel {
|
||||
return null;
|
||||
}
|
||||
const wrapper = this.createNode(schema);
|
||||
if (isNodeParent(wrapper)) {
|
||||
if (wrapper.isParental()) {
|
||||
const first = nodes[0];
|
||||
// TODO: check nesting rules x 2
|
||||
insertChild(first.parent!, wrapper, first.index);
|
||||
@ -270,11 +308,15 @@ export class DocumentModel {
|
||||
}
|
||||
|
||||
import(schema: RootSchema, checkId = false) {
|
||||
this.rootNode.import(schema, checkId);
|
||||
this.rootNode.import(schema as any, checkId);
|
||||
// todo: purge something
|
||||
// todo: select added and active track added
|
||||
}
|
||||
|
||||
export(stage: TransformStage = TransformStage.Serilize) {
|
||||
return this.rootNode.export(stage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出节点数据
|
||||
*/
|
||||
@ -376,7 +418,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 打开,已载入,默认建立时就打开状态,除非手动关闭
|
||||
*/
|
||||
open(): void {
|
||||
open(): DocumentModel {
|
||||
const originState = this._opened;
|
||||
this._opened = true;
|
||||
if (originState === false) {
|
||||
@ -387,6 +429,7 @@ export class DocumentModel {
|
||||
} else {
|
||||
this.project.checkExclusive(this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -409,7 +452,7 @@ export class DocumentModel {
|
||||
// todo:
|
||||
}
|
||||
|
||||
checkNesting(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
checkNesting(dropTarget: ParentalNode, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
let items: Array<Node | NodeSchema>;
|
||||
if (isDragNodeDataObject(dragObject)) {
|
||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||
@ -419,7 +462,7 @@ export class DocumentModel {
|
||||
return items.every((item) => this.checkNestingDown(dropTarget, item));
|
||||
}
|
||||
|
||||
checkDropTarget(dropTarget: NodeParent, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
checkDropTarget(dropTarget: ParentalNode, dragObject: DragNodeObject | DragNodeDataObject): boolean {
|
||||
let items: Array<Node | NodeSchema>;
|
||||
if (isDragNodeDataObject(dragObject)) {
|
||||
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
|
||||
@ -432,7 +475,7 @@ export class DocumentModel {
|
||||
/**
|
||||
* 检查对象对父级的要求,涉及配置 parentWhitelist
|
||||
*/
|
||||
checkNestingUp(parent: NodeParent, obj: NodeSchema | Node): boolean {
|
||||
checkNestingUp(parent: ParentalNode, obj: NodeSchema | Node): boolean {
|
||||
if (isNode(obj) || isNodeSchema(obj)) {
|
||||
const config = isNode(obj) ? obj.componentMeta : this.getComponentMeta(obj.componentName);
|
||||
if (config) {
|
||||
@ -446,10 +489,75 @@ export class DocumentModel {
|
||||
/**
|
||||
* 检查投放位置对子级的要求,涉及配置 childWhitelist
|
||||
*/
|
||||
checkNestingDown(parent: NodeParent, obj: NodeSchema | Node): boolean {
|
||||
checkNestingDown(parent: ParentalNode, obj: NodeSchema | Node): boolean {
|
||||
const config = parent.componentMeta;
|
||||
return config.checkNestingDown(parent, obj) && this.checkNestingUp(parent, obj);
|
||||
}
|
||||
|
||||
// ======= compatibles for vision
|
||||
getRoot() {
|
||||
return this.rootNode;
|
||||
}
|
||||
|
||||
// add toData
|
||||
toData() {
|
||||
const node = this.project?.currentDocument?.export(TransformStage.Save);
|
||||
return { componentsTree: [node] };
|
||||
}
|
||||
|
||||
getHistory(): History {
|
||||
return this.history;
|
||||
}
|
||||
|
||||
get root() {
|
||||
return this.rootNode;
|
||||
}
|
||||
|
||||
onRendererReady(fn: (args: any) => void): () => void {
|
||||
this.emitter.on('lowcode_engine_renderer_ready', fn);
|
||||
return () => {
|
||||
this.emitter.removeListener('lowcode_engine_renderer_ready', fn);
|
||||
};
|
||||
}
|
||||
|
||||
setRendererReady(renderer) {
|
||||
this.emitter.emit('lowcode_engine_renderer_ready', renderer);
|
||||
}
|
||||
|
||||
acceptRootNodeVisitor(
|
||||
visitorName: string = 'default',
|
||||
visitorFn: (node: RootNode) => any ) {
|
||||
let visitorResult = {};
|
||||
if (!visitorName) {
|
||||
/* tslint:disable no-console */
|
||||
console.warn('Invalid or empty RootNodeVisitor name.');
|
||||
}
|
||||
try {
|
||||
visitorResult = visitorFn.call(this, this.rootNode);
|
||||
this.rootNodeVisitorMap[visitorName] = visitorResult;
|
||||
} catch (e) {
|
||||
console.error('RootNodeVisitor is not valid.');
|
||||
}
|
||||
return visitorResult;
|
||||
}
|
||||
|
||||
getRootNodeVisitor(name: string) {
|
||||
return this.rootNodeVisitorMap[name];
|
||||
}
|
||||
|
||||
onNodeCreate(func: (node: Node) => void) {
|
||||
this.emitter.on('nodecreate', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('nodecreate', func);
|
||||
};
|
||||
}
|
||||
|
||||
onNodeDestroy(func: (node: Node) => void) {
|
||||
this.emitter.on('nodedestroy', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('nodedestroy', func);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function isDocumentModel(obj: any): obj is DocumentModel {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer } from '@ali/lowcode-globals';
|
||||
import { observer } from '@ali/lowcode-editor-core';
|
||||
import { DocumentModel } from './document-model';
|
||||
import { BuiltinSimulatorHostView } from '../builtin-simulator';
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { NodeSchema, autorun, Reaction, untracked } from '@ali/lowcode-globals';
|
||||
import { autorun, Reaction, untracked, globalContext, Editor } from '@ali/lowcode-editor-core';
|
||||
import { NodeSchema } from '@ali/lowcode-types';
|
||||
|
||||
// TODO: cache to localStorage
|
||||
|
||||
@ -113,6 +114,11 @@ export class History {
|
||||
}
|
||||
const cursor = this.session.cursor - 1;
|
||||
this.go(cursor);
|
||||
const editor = globalContext.get(Editor);
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
editor.emit('history.back', cursor);
|
||||
}
|
||||
|
||||
forward() {
|
||||
@ -121,6 +127,11 @@ export class History {
|
||||
}
|
||||
const cursor = this.session.cursor + 1;
|
||||
this.go(cursor);
|
||||
const editor = globalContext.get(Editor);
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
editor.emit('history.forward', cursor);
|
||||
}
|
||||
|
||||
savePoint() {
|
||||
@ -173,6 +184,10 @@ export class History {
|
||||
this.emitter.removeAllListeners();
|
||||
this.records = [];
|
||||
}
|
||||
|
||||
isModified() {
|
||||
return this.point !== this.session.cursor;
|
||||
}
|
||||
}
|
||||
|
||||
class Session {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { obx, computed, TitleContent } from '@ali/lowcode-globals';
|
||||
import { uniqueId } from '@ali/lowcode-globals';
|
||||
import { obx, computed } from '@ali/lowcode-editor-core';
|
||||
import { uniqueId } from '@ali/lowcode-utils';
|
||||
import { TitleContent } from '@ali/lowcode-types';
|
||||
import { Node } from './node';
|
||||
import { intl } from '../../locale';
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
export * from './exclusive-group';
|
||||
export * from './node';
|
||||
export * from './node-children';
|
||||
export * from './root-node';
|
||||
export * from './props/prop';
|
||||
export * from './props/prop-stash';
|
||||
export * from './props/props';
|
||||
export * from './transform-stage';
|
||||
|
||||
135
packages/designer/src/document/node/modalNodesManager.ts
Normal file
135
packages/designer/src/document/node/modalNodesManager.ts
Normal file
@ -0,0 +1,135 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { Node } from './node';
|
||||
import { DocumentModel } from '../document-model';
|
||||
|
||||
function getModalNodes(node: Node) {
|
||||
let nodes: any = [];
|
||||
const prototype = node.getPrototype();
|
||||
if (prototype && prototype.isModal()) {
|
||||
nodes.push(node);
|
||||
}
|
||||
const children = node.getChildren();
|
||||
if (children) {
|
||||
children.forEach((child) => {
|
||||
nodes = nodes.concat(getModalNodes(child));
|
||||
});
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export default class ModalNodesManager {
|
||||
public willDestroy: any;
|
||||
|
||||
private page: DocumentModel;
|
||||
private modalNodes: [Node];
|
||||
private nodeRemoveEvents: any;
|
||||
private emitter: EventEmitter;
|
||||
|
||||
constructor(page: DocumentModel) {
|
||||
this.page = page;
|
||||
this.emitter = new EventEmitter();
|
||||
this.nodeRemoveEvents = {};
|
||||
this.setNodes();
|
||||
this.hideModalNodes();
|
||||
this.willDestroy = [
|
||||
page.onNodeCreate((node) => this.addNode(node)),
|
||||
page.onNodeDestroy((node) => this.removeNode(node)),
|
||||
];
|
||||
}
|
||||
|
||||
public getModalNodes() {
|
||||
return this.modalNodes;
|
||||
}
|
||||
|
||||
public getVisibleModalNode() {
|
||||
const visibleNode = this.modalNodes
|
||||
? this.modalNodes.find((node: Node) => {
|
||||
return !node.getExtraProp('hidden');
|
||||
})
|
||||
: null;
|
||||
return visibleNode;
|
||||
}
|
||||
|
||||
public hideModalNodes() {
|
||||
if (this.modalNodes) {
|
||||
this.modalNodes.forEach((node: Node) => {
|
||||
node.getExtraProp('hidden')?.setValue(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public setVisible(node: Node) {
|
||||
this.hideModalNodes();
|
||||
node.getExtraProp('hidden')?.setValue(false);
|
||||
}
|
||||
|
||||
public setInvisible(node: Node) {
|
||||
node.getExtraProp('hidden')?.setValue(true);
|
||||
}
|
||||
|
||||
public onVisibleChange(func: () => any) {
|
||||
this.emitter.on('visibleChange', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('visibleChange', func);
|
||||
};
|
||||
}
|
||||
|
||||
public onModalNodesChange(func: () => any) {
|
||||
this.emitter.on('modalNodesChange', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('modalNodesChange', func);
|
||||
};
|
||||
}
|
||||
|
||||
private addNode(node: Node) {
|
||||
const prototype = node.getPrototype();
|
||||
if (prototype && prototype.isModal()) {
|
||||
this.hideModalNodes();
|
||||
this.modalNodes.push(node);
|
||||
this.addNodeEvent(node);
|
||||
this.emitter.emit('modalNodesChange');
|
||||
this.emitter.emit('visibleChange');
|
||||
}
|
||||
}
|
||||
|
||||
private removeNode(node: Node) {
|
||||
const prototype = node.getPrototype();
|
||||
if (prototype && prototype.isModal()) {
|
||||
const index = this.modalNodes.indexOf(node);
|
||||
if (index >= 0) {
|
||||
this.modalNodes.splice(index, 1);
|
||||
}
|
||||
this.removeNodeEvent(node);
|
||||
this.emitter.emit('modalNodesChange');
|
||||
if (!node.getExtraProp('hidden')) {
|
||||
this.emitter.emit('visibleChange');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private addNodeEvent(node: Node) {
|
||||
// this.nodeRemoveEvents[node.getId()] =
|
||||
// node.onStatusChange((status: any, field: any) => {
|
||||
// if (field === 'visibility') {
|
||||
// this.emitter.emit('visibleChange');
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
private removeNodeEvent(node: Node) {
|
||||
// if (this.nodeRemoveEvents[node.getId()]) {
|
||||
// this.nodeRemoveEvents[node.getId()]();
|
||||
// delete this.nodeRemoveEvents[node.getId()];
|
||||
// }
|
||||
}
|
||||
|
||||
private setNodes() {
|
||||
const nodes = getModalNodes(this.page.getRoot());
|
||||
this.modalNodes = nodes;
|
||||
this.modalNodes.forEach((node: Node) => {
|
||||
this.addNodeEvent(node);
|
||||
});
|
||||
|
||||
this.emitter.emit('modalNodesChange');
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,15 @@
|
||||
import { NodeData, isNodeSchema, obx, computed } from '@ali/lowcode-globals';
|
||||
import { Node, NodeParent } from './node';
|
||||
import { obx, computed } from '@ali/lowcode-editor-core';
|
||||
import { Node, ParentalNode } from './node';
|
||||
import { TransformStage } from './transform-stage';
|
||||
import { NodeData, isNodeSchema } from '@ali/lowcode-types';
|
||||
import { shallowEqual } from '@ali/lowcode-utils';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export class NodeChildren {
|
||||
@obx.val private children: Node[];
|
||||
constructor(readonly owner: NodeParent, data: NodeData | NodeData[]) {
|
||||
private emitter = new EventEmitter();
|
||||
|
||||
constructor(readonly owner: ParentalNode, data: NodeData | NodeData[]) {
|
||||
this.children = (Array.isArray(data) ? data : [data]).map(child => {
|
||||
return this.owner.document.createNode(child);
|
||||
});
|
||||
@ -15,10 +21,16 @@ export class NodeChildren {
|
||||
|
||||
/**
|
||||
* 导出 schema
|
||||
* @param serialize 序列化,加 id 标识符,用于储存为操作记录
|
||||
*/
|
||||
export(serialize = false): NodeData[] {
|
||||
return this.children.map(node => node.export(serialize));
|
||||
export(stage: TransformStage = TransformStage.Save): NodeData[] {
|
||||
return this.children.map(node => {
|
||||
const data = node.export(stage);
|
||||
if (node.isLeaf() && TransformStage.Save === stage) {
|
||||
// FIXME: filter empty
|
||||
return data.children as NodeData;
|
||||
}
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
import(data?: NodeData | NodeData[], checkId = false) {
|
||||
@ -44,6 +56,9 @@ export class NodeChildren {
|
||||
|
||||
this.children = children;
|
||||
this.interalInitParent();
|
||||
if (!shallowEqual(children, originChildren)) {
|
||||
this.emitter.emit('change');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,6 +93,7 @@ export class NodeChildren {
|
||||
deleted.internalSetParent(null);
|
||||
deleted.purge();
|
||||
}
|
||||
this.emitter.emit('change');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -110,6 +126,8 @@ export class NodeChildren {
|
||||
children.splice(index, 0, node);
|
||||
}
|
||||
|
||||
this.emitter.emit('change');
|
||||
|
||||
// check condition group
|
||||
if (node.conditionGroup) {
|
||||
if (
|
||||
@ -140,6 +158,13 @@ export class NodeChildren {
|
||||
return this.children.indexOf(node);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
splice(start: number, deleteCount: number, node: Node): Node[] {
|
||||
return this.children.splice(start, deleteCount, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引获得节点
|
||||
*/
|
||||
@ -195,6 +220,60 @@ export class NodeChildren {
|
||||
});
|
||||
}
|
||||
|
||||
every(fn: (item: Node, index: number) => any): boolean {
|
||||
return this.children.every((child, index) => fn(child, index));
|
||||
}
|
||||
|
||||
some(fn: (item: Node, index: number) => any): boolean {
|
||||
return this.children.some((child, index) => fn(child, index));
|
||||
}
|
||||
|
||||
filter(fn: (item: Node, index: number) => item is Node) {
|
||||
return this.children.filter(fn);
|
||||
}
|
||||
|
||||
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
|
||||
let changed = false;
|
||||
if (remover) {
|
||||
const willRemove = this.children.filter(remover);
|
||||
if (willRemove.length > 0) {
|
||||
willRemove.forEach((node) => {
|
||||
const i = this.children.indexOf(node);
|
||||
if (i > -1) {
|
||||
this.children.splice(i, 1);
|
||||
node.remove();
|
||||
}
|
||||
});
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (adder) {
|
||||
const items = adder(this.children);
|
||||
if (items && items.length > 0) {
|
||||
items.forEach((child: NodeData) => {
|
||||
const node = this.owner.document.createNode(child);
|
||||
this.children.push(node);
|
||||
node.internalSetParent(this.owner);
|
||||
});
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (sorter) {
|
||||
this.children = this.children.sort(sorter);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
this.emitter.emit('change');
|
||||
}
|
||||
}
|
||||
|
||||
onChange(fn: () => void) {
|
||||
this.emitter.on('change', fn);
|
||||
return () => {
|
||||
this.emitter.removeListener('change', fn);
|
||||
};
|
||||
}
|
||||
|
||||
private purged = false;
|
||||
/**
|
||||
* 回收销毁
|
||||
@ -206,4 +285,9 @@ export class NodeChildren {
|
||||
this.purged = true;
|
||||
this.children.forEach(child => child.purge());
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag]() {
|
||||
// 保证向前兼容性
|
||||
return "Array";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { obx, computed, autorun } from '@ali/lowcode-editor-core';
|
||||
import {
|
||||
isDOMText,
|
||||
isJSExpression,
|
||||
@ -6,15 +7,21 @@ import {
|
||||
PropsList,
|
||||
NodeData,
|
||||
TitleContent,
|
||||
obx,
|
||||
computed,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { Props, EXTRA_KEY_PREFIX } from './props/props';
|
||||
I18nData,
|
||||
SlotSchema,
|
||||
PageSchema,
|
||||
ComponentSchema,
|
||||
NodeStatus,
|
||||
} from '@ali/lowcode-types';
|
||||
import { Props, getConvertedExtraKey } from './props/props';
|
||||
import { DocumentModel } from '../document-model';
|
||||
import { NodeChildren } from './node-children';
|
||||
import { Prop } from './props/prop';
|
||||
import { ComponentMeta } from '../../component-meta';
|
||||
import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group';
|
||||
import { TransformStage } from './transform-stage';
|
||||
import { ReactElement } from 'react';
|
||||
import { SettingTopEntry } from 'designer/src/designer';
|
||||
|
||||
/**
|
||||
* 基础节点
|
||||
@ -35,8 +42,36 @@ import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group';
|
||||
* locked can not select/hover/ item on canvas but can control on outline
|
||||
* hidden not visible on canvas
|
||||
* slotArgs like loopArgs, for slot node
|
||||
*
|
||||
* 根容器节点
|
||||
*
|
||||
* [Node Properties]
|
||||
* componentName: Page/Block/Component
|
||||
* props
|
||||
* children
|
||||
*
|
||||
* [Root Container Extra Properties]
|
||||
* fileName
|
||||
* meta
|
||||
* state
|
||||
* defaultProps
|
||||
* dataSource
|
||||
* lifeCycles
|
||||
* methods
|
||||
* css
|
||||
*
|
||||
* [Directives **not used**]
|
||||
* loop
|
||||
* loopArgs
|
||||
* condition
|
||||
* ------- future support -----
|
||||
* conditionGroup
|
||||
* title
|
||||
* ignore
|
||||
* locked
|
||||
* hidden
|
||||
*/
|
||||
export class Node {
|
||||
export class Node<Schema extends NodeSchema = NodeSchema> {
|
||||
/**
|
||||
* 是节点实例
|
||||
*/
|
||||
@ -63,11 +98,15 @@ export class Node {
|
||||
*/
|
||||
readonly props: Props;
|
||||
protected _children?: NodeChildren;
|
||||
@obx.ref private _parent: NodeParent | null = null;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
private _addons: { [key: string]: any } = {};
|
||||
@obx.ref private _parent: ParentalNode | null = null;
|
||||
/**
|
||||
* 父级节点
|
||||
*/
|
||||
get parent(): NodeParent | null {
|
||||
get parent(): ParentalNode | null {
|
||||
return this._parent;
|
||||
}
|
||||
/**
|
||||
@ -86,7 +125,7 @@ export class Node {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@computed get title(): TitleContent {
|
||||
@computed get title(): string | I18nData | ReactElement {
|
||||
let t = this.getExtraProp('title');
|
||||
if (!t && this.componentMeta.descriptor) {
|
||||
t = this.getProp(this.componentMeta.descriptor, false);
|
||||
@ -100,53 +139,127 @@ export class Node {
|
||||
return this.componentMeta.title;
|
||||
}
|
||||
|
||||
get isSlotRoot(): boolean {
|
||||
return this._slotFor != null;
|
||||
get icon() {
|
||||
return this.componentMeta.icon;
|
||||
}
|
||||
|
||||
constructor(readonly document: DocumentModel, nodeSchema: NodeSchema, slotFor?: Prop) {
|
||||
readonly settingEntry: SettingTopEntry;
|
||||
|
||||
constructor(readonly document: DocumentModel, nodeSchema: Schema) {
|
||||
const { componentName, id, children, props, ...extras } = nodeSchema;
|
||||
this.id = id || `node$${document.nextId()}`;
|
||||
this.id = id || `node_${document.nextId()}`;
|
||||
this.componentName = componentName;
|
||||
this._slotFor = slotFor;
|
||||
let _props: Props;
|
||||
if (isNodeParent(this)) {
|
||||
_props = new Props(this, props, extras);
|
||||
this._children = new NodeChildren(this as NodeParent, children || []);
|
||||
this._children.interalInitParent();
|
||||
} else {
|
||||
_props = new Props(this, {
|
||||
if (this.componentName === 'Leaf') {
|
||||
this.props = new Props(this, {
|
||||
children: isDOMText(children) || isJSExpression(children) ? children : '',
|
||||
});
|
||||
} else {
|
||||
this.props = new Props(this, props, extras);
|
||||
this._children = new NodeChildren(this as ParentalNode, this.initialChildren(children));
|
||||
this._children.interalInitParent();
|
||||
this.props.import(this.transformProps(props || {}), extras);
|
||||
this.setupAutoruns();
|
||||
}
|
||||
this.props = _props;
|
||||
|
||||
this.settingEntry = this.document.designer.createSettingEntry([ this ]);
|
||||
}
|
||||
|
||||
private transformProps(props: any): any {
|
||||
// FIXME! support PropsList
|
||||
return this.document.designer.transformProps(props, this, TransformStage.Init);
|
||||
// TODO: run transducers in metadata.experimental
|
||||
}
|
||||
|
||||
private autoruns?: Array<() => void>;
|
||||
private setupAutoruns() {
|
||||
const autoruns = this.componentMeta.getMetadata().experimental?.autoruns;
|
||||
if (!autoruns || autoruns.length < 1) {
|
||||
return;
|
||||
}
|
||||
this.autoruns = autoruns.map((item) => {
|
||||
return autorun(() => {
|
||||
item.autorun(this.props.get(item.name, true) as any);
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
private initialChildren(children: any): NodeData[] {
|
||||
// FIXME! this is dirty code
|
||||
if (children == null) {
|
||||
const initialChildren = this.componentMeta.getMetadata().experimental?.initialChildren;
|
||||
if (initialChildren) {
|
||||
if (typeof initialChildren === 'function') {
|
||||
return initialChildren(this as any) || [];
|
||||
}
|
||||
return initialChildren;
|
||||
}
|
||||
}
|
||||
return children || [];
|
||||
}
|
||||
|
||||
isContainer(): boolean {
|
||||
return this.isParental() && this.componentMeta.isContainer;
|
||||
}
|
||||
|
||||
isRoot(): boolean {
|
||||
return this.document.rootNode == (this as any);
|
||||
}
|
||||
|
||||
isPage(): boolean {
|
||||
return this.isRoot() && this.componentName === 'Page';
|
||||
}
|
||||
|
||||
isComponent(): boolean {
|
||||
return this.isRoot() && this.componentName === 'Component';
|
||||
}
|
||||
|
||||
isSlot(): boolean {
|
||||
return this._slotFor != null && this.componentName === 'Slot';
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否一个父亲类节点
|
||||
*/
|
||||
get isNodeParent(): boolean {
|
||||
return this.componentName !== 'Leaf';
|
||||
isParental(): this is ParentalNode {
|
||||
return !this.isLeaf();
|
||||
}
|
||||
|
||||
/**
|
||||
* 终端节点,内容一般为 文字 或者 表达式
|
||||
*/
|
||||
isLeaf(): this is LeafNode {
|
||||
return this.componentName === 'Leaf';
|
||||
}
|
||||
|
||||
internalSetWillPurge() {
|
||||
this.internalSetParent(null);
|
||||
this.document.addWillPurge(this);
|
||||
}
|
||||
/**
|
||||
* 内部方法,请勿使用
|
||||
*/
|
||||
internalSetParent(parent: NodeParent | null) {
|
||||
internalSetParent(parent: ParentalNode | null) {
|
||||
if (this._parent === parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._parent && !this.isSlotRoot) {
|
||||
this._parent.children.delete(this);
|
||||
if (this._parent) {
|
||||
if (this.isSlot()) {
|
||||
this._parent.removeSlot(this, false);
|
||||
} else {
|
||||
this._parent.children.delete(this);
|
||||
}
|
||||
}
|
||||
|
||||
this._parent = parent;
|
||||
if (parent && !this.conditionGroup) {
|
||||
// initial conditionGroup
|
||||
const grp = this.getExtraProp('conditionGroup', false)?.getAsString();
|
||||
if (grp) {
|
||||
this.setConditionGroup(grp);
|
||||
if (parent) {
|
||||
this.document.removeWillPurge(this);
|
||||
if (!this.conditionGroup) {
|
||||
// initial conditionGroup
|
||||
const grp = this.getExtraProp('conditionGroup', false)?.getAsString();
|
||||
if (grp) {
|
||||
this.setConditionGroup(grp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -156,6 +269,9 @@ export class Node {
|
||||
this._slotFor = slotFor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联属性
|
||||
*/
|
||||
get slotFor() {
|
||||
return this._slotFor;
|
||||
}
|
||||
@ -164,8 +280,12 @@ export class Node {
|
||||
* 移除当前节点
|
||||
*/
|
||||
remove() {
|
||||
if (this.parent && !this.isSlotRoot) {
|
||||
this.parent.children.delete(this, true);
|
||||
if (this.parent) {
|
||||
if (this.isSlot()) {
|
||||
this.parent.removeSlot(this, true);
|
||||
} else {
|
||||
this.parent.children.delete(this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,9 +301,9 @@ export class Node {
|
||||
*/
|
||||
hover(flag = true) {
|
||||
if (flag) {
|
||||
this.document.designer.hovering.hover(this);
|
||||
this.document.designer.detecting.capture(this);
|
||||
} else {
|
||||
this.document.designer.hovering.unhover(this);
|
||||
this.document.designer.detecting.release(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,34 +315,19 @@ export class Node {
|
||||
}
|
||||
|
||||
@computed get propsData(): PropsMap | PropsList | null {
|
||||
if (!this.isNodeParent || this.componentName === 'Fragment') {
|
||||
if (!this.isParental() || this.componentName === 'Fragment') {
|
||||
return null;
|
||||
}
|
||||
return this.props.export(true).props || null;
|
||||
return this.props.export(TransformStage.Serilize).props || null;
|
||||
}
|
||||
|
||||
isContainer() {
|
||||
return this.isNodeParent && this.componentMeta.isContainer;
|
||||
@obx.val _slots: Node[] = [];
|
||||
@computed hasSlots() {
|
||||
return this._slots.length > 0;
|
||||
}
|
||||
|
||||
@computed isSlotContainer() {
|
||||
for (const item of this.props) {
|
||||
if (item.type === 'slot') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@computed get slots() {
|
||||
// TODO: optimize recore/obx, array maked every time, donot as changed
|
||||
const slots: Node[] = [];
|
||||
this.props.forEach(item => {
|
||||
if (item.type === 'slot') {
|
||||
slots.push(item.slotNode!);
|
||||
}
|
||||
});
|
||||
return slots;
|
||||
get slots() {
|
||||
return this._slots;
|
||||
}
|
||||
|
||||
@obx.ref private _conditionGroup: ExclusiveGroup | null = null;
|
||||
@ -268,7 +373,7 @@ export class Node {
|
||||
|
||||
@computed hasCondition() {
|
||||
const v = this.getExtraProp('condition', false)?.getValue();
|
||||
return v != null && v !== '';
|
||||
return v != null && v !== '' && v !== true;
|
||||
}
|
||||
|
||||
@computed hasLoop() {
|
||||
@ -276,13 +381,37 @@ export class Node {
|
||||
return v != null && v !== '';
|
||||
}
|
||||
|
||||
wrapWith(schema: NodeSchema) {
|
||||
wrapWith(schema: Schema) {
|
||||
// todo
|
||||
}
|
||||
|
||||
replaceWith(schema: NodeSchema, migrate = true) {
|
||||
replaceWith(schema: Schema, migrate = false): any {
|
||||
// reuse the same id? or replaceSelection
|
||||
//
|
||||
schema = Object.assign({}, migrate ? this.export() : {}, schema);
|
||||
return this.parent?.replaceChild(this, schema);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换子节点
|
||||
*
|
||||
* @param {Node} node
|
||||
* @param {object} data
|
||||
*/
|
||||
replaceChild(node: Node, data: any): Node {
|
||||
if (this.children?.has(node)) {
|
||||
const selected = this.document.selection.has(node.id);
|
||||
|
||||
delete data.id;
|
||||
const newNode = this.document.createNode(data);
|
||||
|
||||
this.insertBefore(newNode, node);
|
||||
node.remove();
|
||||
|
||||
if (selected) {
|
||||
this.document.selection.select(newNode.id);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
getProp(path: string, stash = true): Prop | null {
|
||||
@ -290,7 +419,7 @@ export class Node {
|
||||
}
|
||||
|
||||
getExtraProp(key: string, stash = true): Prop | null {
|
||||
return this.props.get(EXTRA_KEY_PREFIX + key, stash) || null;
|
||||
return this.props.get(getConvertedExtraKey(key), stash) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -307,6 +436,13 @@ export class Node {
|
||||
this.getProp(path, true)!.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除已设置的值
|
||||
*/
|
||||
clearPropValue(path: string): void {
|
||||
this.getProp(path, false)?.unset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置多个属性值,和原有值合并
|
||||
*/
|
||||
@ -362,18 +498,18 @@ export class Node {
|
||||
/**
|
||||
* 获取符合搭建协议-节点 schema 结构
|
||||
*/
|
||||
get schema(): NodeSchema {
|
||||
return this.export(true);
|
||||
get schema(): Schema {
|
||||
return this.export(TransformStage.Save);
|
||||
}
|
||||
|
||||
set schema(data: NodeSchema) {
|
||||
set schema(data: Schema) {
|
||||
this.import(data);
|
||||
}
|
||||
|
||||
import(data: NodeSchema, checkId = false) {
|
||||
import(data: Schema, checkId = false) {
|
||||
const { componentName, id, children, props, ...extras } = data;
|
||||
|
||||
if (isNodeParent(this)) {
|
||||
if (this.isParental()) {
|
||||
this.props.import(props, extras);
|
||||
(this._children as NodeChildren).import(children, checkId);
|
||||
} else {
|
||||
@ -381,34 +517,48 @@ export class Node {
|
||||
}
|
||||
}
|
||||
|
||||
toData() {
|
||||
return this.export();
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出 schema
|
||||
* @param serialize 序列化,加 id 标识符,用于储存为操作记录
|
||||
*/
|
||||
export(serialize = false): NodeSchema {
|
||||
export(stage: TransformStage = TransformStage.Save): Schema {
|
||||
const baseSchema: any = {
|
||||
componentName: this.componentName === 'Leaf' ? 'Fragment' : this.componentName,
|
||||
componentName: this.componentName,
|
||||
};
|
||||
|
||||
if (serialize) {
|
||||
if (stage !== TransformStage.Clone) {
|
||||
baseSchema.id = this.id;
|
||||
}
|
||||
|
||||
if (!isNodeParent(this)) {
|
||||
baseSchema.children = this.props.get('children')?.export(serialize);
|
||||
// FIXME!
|
||||
return baseSchema.children;
|
||||
if (this.isLeaf()) {
|
||||
baseSchema.children = this.props.get('children')?.export(stage);
|
||||
return baseSchema;
|
||||
}
|
||||
|
||||
const { props = {}, extras } = this.props.export(serialize) || {};
|
||||
const schema: any = {
|
||||
...baseSchema,
|
||||
props,
|
||||
const { props = {}, extras } = this.props.export(stage) || {};
|
||||
const _extras_: { [key: string]: any } = {
|
||||
...extras,
|
||||
};
|
||||
if (_extras_) {
|
||||
Object.keys(_extras_).forEach((key) => {
|
||||
const addon = this._addons[key];
|
||||
if (addon) {
|
||||
_extras_[key] = addon();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.children.size > 0) {
|
||||
schema.children = this.children.export(serialize);
|
||||
const schema: any = {
|
||||
...baseSchema,
|
||||
props: this.document.designer.transformProps(props, this, stage),
|
||||
...this.document.designer.transformProps(_extras_, this, stage),
|
||||
};
|
||||
|
||||
if (this.isParental() && this.children.size > 0) {
|
||||
schema.children = this.children.export(stage);
|
||||
}
|
||||
|
||||
return schema;
|
||||
@ -440,6 +590,28 @@ export class Node {
|
||||
return comparePosition(this, otherNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个Slot节点
|
||||
*/
|
||||
removeSlot(slotNode: Node, purge = false): boolean {
|
||||
const i = this._slots.indexOf(slotNode);
|
||||
if (i < 0) {
|
||||
return false;
|
||||
}
|
||||
const deleted = this._slots.splice(i, 1)[0];
|
||||
if (purge) {
|
||||
// should set parent null
|
||||
deleted.internalSetParent(null);
|
||||
deleted.purge();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
addSlot(slotNode: Node) {
|
||||
slotNode.internalSetParent(this as ParentalNode);
|
||||
this._slots.push(slotNode);
|
||||
}
|
||||
|
||||
private purged = false;
|
||||
/**
|
||||
* 是否已销毁
|
||||
@ -460,25 +632,182 @@ export class Node {
|
||||
return;
|
||||
}
|
||||
this.purged = true;
|
||||
if (isNodeParent(this)) {
|
||||
if (this.isParental()) {
|
||||
this.children.purge();
|
||||
}
|
||||
this.autoruns?.forEach((dispose) => dispose());
|
||||
this.props.purge();
|
||||
this.document.internalRemoveAndPurgeNode(this);
|
||||
|
||||
this.document.destroyNode(this);
|
||||
}
|
||||
|
||||
// ======= compatible apis ====
|
||||
isEmpty(): boolean {
|
||||
return this.children ? this.children.isEmpty() : true;
|
||||
}
|
||||
getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
getComponentName() {
|
||||
return this.componentName;
|
||||
}
|
||||
insertBefore(node: Node, ref?: Node) {
|
||||
this.children?.insert(node, ref ? ref.index : null);
|
||||
}
|
||||
insertAfter(node: any, ref?: Node) {
|
||||
if (!isNode(node)) {
|
||||
if (node.getComponentName) {
|
||||
node = this.document.createNode({
|
||||
componentName: node.getComponentName(),
|
||||
});
|
||||
} else {
|
||||
node = this.document.createNode(node);
|
||||
}
|
||||
}
|
||||
this.children?.insert(node, ref ? ref.index + 1 : null);
|
||||
}
|
||||
getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
getIndex() {
|
||||
return this.index;
|
||||
}
|
||||
getNode() {
|
||||
return this;
|
||||
}
|
||||
getRoot() {
|
||||
return this.document.rootNode;
|
||||
}
|
||||
getProps() {
|
||||
return this.props;
|
||||
}
|
||||
|
||||
onChildrenChange(fn: () => void) {
|
||||
return this.children?.onChange(fn);
|
||||
}
|
||||
|
||||
mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any) {
|
||||
this.children?.mergeChildren(remover, adder, sorter);
|
||||
}
|
||||
|
||||
@obx.val status: NodeStatus = {
|
||||
inPlaceEditing: false,
|
||||
locking: false,
|
||||
pseudo: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getStatus(field?: keyof NodeStatus) {
|
||||
if (field && this.status[field] != null) {
|
||||
return this.status[field];
|
||||
}
|
||||
|
||||
return this.status;
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
setStatus(field: keyof NodeStatus, flag: boolean) {
|
||||
if (!this.status.hasOwnProperty(field)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flag !== this.status[field]) {
|
||||
this.status[field] = flag;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getDOMNode(): any {
|
||||
const instance = this.document.simulator?.getComponentInstances(this)?.[0];
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
return this.document.simulator?.findDOMNodes(instance)?.[0];
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getPage() {
|
||||
console.warn('getPage is deprecated, use document instead');
|
||||
return this.document;
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getSuitablePlace(node: Node, ref: any): any {
|
||||
// TODO:
|
||||
if (this.isRoot()) {
|
||||
return { container: this, ref };
|
||||
}
|
||||
return { container: this.parent, ref: this };
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getAddonData(key: string) {
|
||||
const addon = this._addons[key];
|
||||
if (addon) {
|
||||
return addon();
|
||||
}
|
||||
return this.getExtraProp(key)?.value;
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
registerAddon(key: string, exportData: any) {
|
||||
if (this._addons[key]) {
|
||||
throw new Error(`node addon ${key} exist`);
|
||||
}
|
||||
|
||||
this._addons[key] = exportData;
|
||||
}
|
||||
|
||||
getRect(): DOMRect | null {
|
||||
if (this.isRoot()) {
|
||||
return this.document.simulator?.viewport.contentBounds || null;
|
||||
}
|
||||
return this.document.simulator?.computeRect(this) || null;
|
||||
}
|
||||
|
||||
getPrototype() {
|
||||
return this.componentMeta.prototype;
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return this.icon;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
|
||||
export interface NodeParent extends Node {
|
||||
export interface ParentalNode<T extends NodeSchema = NodeSchema> extends Node<T> {
|
||||
readonly children: NodeChildren;
|
||||
readonly props: Props;
|
||||
}
|
||||
export interface LeafNode extends Node {
|
||||
readonly children: null;
|
||||
}
|
||||
|
||||
export type SlotNode = ParentalNode<SlotSchema>;
|
||||
export type PageNode = ParentalNode<PageSchema>;
|
||||
export type ComponentNode = ParentalNode<ComponentSchema>;
|
||||
export type RootNode = PageNode | ComponentNode;
|
||||
|
||||
export function isNode(node: any): node is Node {
|
||||
return node && node.isNode;
|
||||
}
|
||||
|
||||
export function isNodeParent(node: Node): node is NodeParent {
|
||||
return node.isNodeParent;
|
||||
export function isRootNode(node: Node): node is RootNode {
|
||||
return node && node.isRoot();
|
||||
}
|
||||
|
||||
export function getZLevelTop(child: Node, zLevel: number): Node | null {
|
||||
@ -501,7 +830,7 @@ export function contains(node1: Node, node2: Node): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!node1.isNodeParent || !node2.parent) {
|
||||
if (!node1.isParental || !node2.parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -550,10 +879,10 @@ export function comparePosition(node1: Node, node2: Node): PositionNO {
|
||||
return PositionNO.BeforeOrAfter;
|
||||
}
|
||||
|
||||
export function insertChild(container: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
export function insertChild(container: ParentalNode, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {
|
||||
let node: Node;
|
||||
if (isNode(thing) && (copy || thing.isSlotRoot)) {
|
||||
thing = thing.export(false);
|
||||
if (isNode(thing) && (copy || thing.isSlot())) {
|
||||
thing = thing.export(TransformStage.Clone);
|
||||
}
|
||||
if (isNode(thing)) {
|
||||
node = thing;
|
||||
@ -567,7 +896,7 @@ export function insertChild(container: NodeParent, thing: Node | NodeData, at?:
|
||||
}
|
||||
|
||||
export function insertChildren(
|
||||
container: NodeParent,
|
||||
container: ParentalNode,
|
||||
nodes: Node[] | NodeData[],
|
||||
at?: number | null,
|
||||
copy?: boolean,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { obx, autorun, untracked, computed } from '@ali/lowcode-globals';
|
||||
import { obx, autorun, untracked, computed } from '@ali/lowcode-editor-core';
|
||||
import { Prop, IPropParent, UNSET } from './prop';
|
||||
import { Props } from './props';
|
||||
import { Node } from '../node';
|
||||
|
||||
export type PendingItem = Prop[];
|
||||
export class PropStash implements IPropParent {
|
||||
@ -15,8 +16,10 @@ export class PropStash implements IPropParent {
|
||||
return maps;
|
||||
}
|
||||
private willPurge: () => void;
|
||||
readonly owner: Node;
|
||||
|
||||
constructor(readonly props: Props, write: (item: Prop) => void) {
|
||||
this.owner = props.owner;
|
||||
this.willPurge = autorun(() => {
|
||||
if (this.space.size < 1) {
|
||||
return;
|
||||
|
||||
@ -1,20 +1,11 @@
|
||||
import {
|
||||
CompositeValue,
|
||||
isJSExpression,
|
||||
isJSSlot,
|
||||
NodeData,
|
||||
isNodeSchema,
|
||||
untracked,
|
||||
computed,
|
||||
obx
|
||||
} from '@ali/lowcode-globals';
|
||||
import { uniqueId } from '@ali/lowcode-globals';
|
||||
import { isPlainObject } from '@ali/lowcode-globals';
|
||||
import { hasOwnProperty } from '@ali/lowcode-globals';
|
||||
import { untracked, computed, obx } from '@ali/lowcode-editor-core';
|
||||
import { CompositeValue, isJSExpression, isJSSlot, JSSlot, SlotSchema } from '@ali/lowcode-types';
|
||||
import { uniqueId, isPlainObject, hasOwnProperty } from '@ali/lowcode-utils';
|
||||
import { PropStash } from './prop-stash';
|
||||
import { valueToSource } from './value-to-source';
|
||||
import { Props } from './props';
|
||||
import { Node } from '../node';
|
||||
import { SlotNode, Node } from '../node';
|
||||
import { TransformStage } from '../transform-stage';
|
||||
|
||||
export const UNSET = Symbol.for('unset');
|
||||
export type UNSET = typeof UNSET;
|
||||
@ -22,12 +13,35 @@ export type UNSET = typeof UNSET;
|
||||
export interface IPropParent {
|
||||
delete(prop: Prop): void;
|
||||
readonly props: Props;
|
||||
readonly owner: Node;
|
||||
}
|
||||
|
||||
export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | 'slot';
|
||||
|
||||
export class Prop implements IPropParent {
|
||||
readonly isProp = true;
|
||||
readonly owner: Node;
|
||||
|
||||
/**
|
||||
* @see SettingTarget
|
||||
*/
|
||||
getPropValue(propName: string | number): any {
|
||||
return this.get(propName)!.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SettingTarget
|
||||
*/
|
||||
setPropValue(propName: string | number, value: any): void {
|
||||
this.set(propName, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SettingTarget
|
||||
*/
|
||||
clearPropValue(propName: string | number): void {
|
||||
this.get(propName, false)?.unset();
|
||||
}
|
||||
|
||||
readonly id = uniqueId('prop$');
|
||||
|
||||
@ -45,10 +59,10 @@ export class Prop implements IPropParent {
|
||||
* 属性值
|
||||
*/
|
||||
@computed get value(): CompositeValue | UNSET {
|
||||
return this.export(true);
|
||||
return this.export(TransformStage.Serilize);
|
||||
}
|
||||
|
||||
export(serialize = false): CompositeValue | UNSET {
|
||||
export(stage: TransformStage = TransformStage.Save): CompositeValue | UNSET {
|
||||
const type = this._type;
|
||||
|
||||
if (type === 'unset') {
|
||||
@ -60,9 +74,18 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
|
||||
if (type === 'slot') {
|
||||
const schema = this._slotNode!.export(stage);
|
||||
if (stage === TransformStage.Render) {
|
||||
return {
|
||||
type: 'JSSlot',
|
||||
params: schema.params,
|
||||
value: schema,
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 'JSSlot',
|
||||
value: this._slotNode!.export(serialize),
|
||||
params: schema.params,
|
||||
value: schema.children,
|
||||
};
|
||||
}
|
||||
|
||||
@ -72,9 +95,9 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
const maps: any = {};
|
||||
this.items!.forEach((prop, key) => {
|
||||
const v = prop.export(serialize);
|
||||
const v = prop.export(stage);
|
||||
if (v !== UNSET) {
|
||||
maps[key] = v;
|
||||
maps[prop.key == null ? key : prop.key] = v;
|
||||
}
|
||||
});
|
||||
return maps;
|
||||
@ -85,12 +108,12 @@ export class Prop implements IPropParent {
|
||||
return this._value;
|
||||
}
|
||||
return this.items!.map((prop) => {
|
||||
const v = prop.export(serialize);
|
||||
return v === UNSET ? null : v;
|
||||
const v = prop.export(stage);
|
||||
return v === UNSET ? undefined : v;
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _code: string | null = null;
|
||||
@ -103,7 +126,7 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
// todo: JSFunction ...
|
||||
if (this.type === 'slot') {
|
||||
return JSON.stringify(this._slotNode!.export(false));
|
||||
return JSON.stringify(this._slotNode!.export(TransformStage.Save));
|
||||
}
|
||||
return this._code != null ? this._code : JSON.stringify(this.value);
|
||||
}
|
||||
@ -153,7 +176,7 @@ export class Prop implements IPropParent {
|
||||
this._code = null;
|
||||
const t = typeof val;
|
||||
if (val == null) {
|
||||
this._value = null;
|
||||
this._value = undefined;
|
||||
this._type = 'literal';
|
||||
} else if (t === 'string' || t === 'number' || t === 'boolean') {
|
||||
this._type = 'literal';
|
||||
@ -161,7 +184,7 @@ export class Prop implements IPropParent {
|
||||
this._type = 'list';
|
||||
} else if (isPlainObject(val)) {
|
||||
if (isJSSlot(val)) {
|
||||
this.setAsSlot(val.value);
|
||||
this.setAsSlot(val);
|
||||
return;
|
||||
}
|
||||
if (isJSExpression(val)) {
|
||||
@ -169,7 +192,6 @@ export class Prop implements IPropParent {
|
||||
} else {
|
||||
this._type = 'map';
|
||||
}
|
||||
this._type = 'map';
|
||||
} else {
|
||||
this._type = 'expression';
|
||||
this._value = {
|
||||
@ -181,9 +203,9 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
|
||||
@computed getValue(): CompositeValue {
|
||||
const v = this.export(true);
|
||||
const v = this.export(TransformStage.Serilize);
|
||||
if (v === UNSET) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@ -204,24 +226,25 @@ export class Prop implements IPropParent {
|
||||
}
|
||||
}
|
||||
|
||||
private _slotNode?: Node;
|
||||
private _slotNode?: SlotNode;
|
||||
get slotNode() {
|
||||
return this._slotNode;
|
||||
}
|
||||
setAsSlot(data: NodeData) {
|
||||
setAsSlot(data: JSSlot) {
|
||||
this._type = 'slot';
|
||||
if (
|
||||
this._slotNode &&
|
||||
isNodeSchema(data) &&
|
||||
(!data.id || this._slotNode.id === data.id) &&
|
||||
this._slotNode.componentName === data.componentName
|
||||
) {
|
||||
this._slotNode.import(data);
|
||||
const slotSchema: SlotSchema = {
|
||||
componentName: 'Slot',
|
||||
title: data.title,
|
||||
params: data.params,
|
||||
children: data.value,
|
||||
};
|
||||
if (this._slotNode) {
|
||||
this._slotNode.import(slotSchema);
|
||||
} else {
|
||||
this._slotNode?.internalSetParent(null);
|
||||
const owner = this.props.owner;
|
||||
this._slotNode = owner.document.createNode(data, this);
|
||||
this._slotNode.internalSetParent(owner as any);
|
||||
this._slotNode = owner.document.createNode<SlotNode>(slotSchema);
|
||||
owner.addSlot(this._slotNode);
|
||||
this._slotNode.internalSetSlotFor(this);
|
||||
}
|
||||
this.dispose();
|
||||
}
|
||||
@ -244,7 +267,9 @@ export class Prop implements IPropParent {
|
||||
return typeof this.key === 'string' && this.key.charAt(0) === '!';
|
||||
}
|
||||
|
||||
// TODO: improve this logic
|
||||
/**
|
||||
* @returns 0: the same 1: maybe & like 2: not the same
|
||||
*/
|
||||
compare(other: Prop | null): number {
|
||||
if (!other || other.isUnset()) {
|
||||
return this.isUnset() ? 0 : 2;
|
||||
@ -326,6 +351,7 @@ export class Prop implements IPropParent {
|
||||
key?: string | number,
|
||||
spread = false,
|
||||
) {
|
||||
this.owner = parent.owner;
|
||||
this.props = parent.props;
|
||||
if (value !== UNSET) {
|
||||
this.setValue(value);
|
||||
@ -338,7 +364,7 @@ export class Prop implements IPropParent {
|
||||
* 获取某个属性
|
||||
* @param stash 如果不存在,临时获取一个待写入
|
||||
*/
|
||||
get(path: string | number, stash = true): Prop | null {
|
||||
get(path: string | number, stash: boolean = true): Prop | null {
|
||||
const type = this._type;
|
||||
if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) {
|
||||
return null;
|
||||
@ -585,6 +611,14 @@ export class Prop implements IPropParent {
|
||||
return isMap ? fn(item, item.key) : fn(item, index);
|
||||
});
|
||||
}
|
||||
|
||||
getProps() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
getNode() {
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
|
||||
export function isProp(obj: any): obj is Prop {
|
||||
|
||||
@ -1,9 +1,25 @@
|
||||
import { PropsMap, PropsList, CompositeValue, computed, obx, uniqueId } from '@ali/lowcode-globals';
|
||||
import { computed, obx } from '@ali/lowcode-editor-core';
|
||||
import { PropsMap, PropsList, CompositeValue } from '@ali/lowcode-types';
|
||||
import { uniqueId } from '@ali/lowcode-utils';
|
||||
import { PropStash } from './prop-stash';
|
||||
import { Prop, IPropParent, UNSET } from './prop';
|
||||
import { Node } from '../node';
|
||||
import { TransformStage } from '../transform-stage';
|
||||
|
||||
export const EXTRA_KEY_PREFIX = '__';
|
||||
export const EXTRA_KEY_PREFIX = '___';
|
||||
export function getConvertedExtraKey(key: string): string {
|
||||
if (!key) {
|
||||
return '';
|
||||
}
|
||||
let _key = key;
|
||||
if (key.indexOf('.') > 0) {
|
||||
_key = key.split('.')[0];
|
||||
}
|
||||
return EXTRA_KEY_PREFIX + _key + EXTRA_KEY_PREFIX + key.substr(_key.length);
|
||||
}
|
||||
export function getOriginalExtraKey(key: string): string {
|
||||
return key.replace(new RegExp(`${EXTRA_KEY_PREFIX}`, 'g'), '');
|
||||
}
|
||||
|
||||
export class Props implements IPropParent {
|
||||
readonly id = uniqueId('props');
|
||||
@ -47,7 +63,7 @@ export class Props implements IPropParent {
|
||||
}
|
||||
if (extras) {
|
||||
Object.keys(extras).forEach(key => {
|
||||
this.items.push(new Prop(this, (extras as any)[key], EXTRA_KEY_PREFIX + key));
|
||||
this.items.push(new Prop(this, (extras as any)[key], getConvertedExtraKey(key)));
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -67,7 +83,7 @@ export class Props implements IPropParent {
|
||||
}
|
||||
if (extras) {
|
||||
Object.keys(extras).forEach(key => {
|
||||
this.items.push(new Prop(this, (extras as any)[key], EXTRA_KEY_PREFIX + key));
|
||||
this.items.push(new Prop(this, (extras as any)[key], getConvertedExtraKey(key)));
|
||||
});
|
||||
}
|
||||
originItems.forEach(item => item.purge());
|
||||
@ -79,7 +95,7 @@ export class Props implements IPropParent {
|
||||
});
|
||||
}
|
||||
|
||||
export(serialize = false): { props?: PropsMap | PropsList; extras?: object } {
|
||||
export(stage: TransformStage = TransformStage.Save): { props?: PropsMap | PropsList; extras?: object } {
|
||||
if (this.items.length < 1) {
|
||||
return {};
|
||||
}
|
||||
@ -88,13 +104,13 @@ export class Props implements IPropParent {
|
||||
if (this.type === 'list') {
|
||||
props = [];
|
||||
this.items.forEach(item => {
|
||||
let value = item.export(serialize);
|
||||
let value = item.export(stage);
|
||||
if (value === UNSET) {
|
||||
value = null;
|
||||
value = undefined;
|
||||
}
|
||||
let name = item.key as string;
|
||||
if (name && typeof name === 'string' && name.startsWith(EXTRA_KEY_PREFIX)) {
|
||||
name = name.substr(EXTRA_KEY_PREFIX.length);
|
||||
name = getOriginalExtraKey(name);
|
||||
extras[name] = value;
|
||||
} else {
|
||||
props.push({
|
||||
@ -111,12 +127,12 @@ export class Props implements IPropParent {
|
||||
// todo ...spread
|
||||
return;
|
||||
}
|
||||
let value = item.export(serialize);
|
||||
let value = item.export(stage);
|
||||
if (value === UNSET) {
|
||||
value = null;
|
||||
value = undefined;
|
||||
}
|
||||
if (typeof name === 'string' && name.startsWith(EXTRA_KEY_PREFIX)) {
|
||||
name = name.substr(EXTRA_KEY_PREFIX.length);
|
||||
name = getOriginalExtraKey(name);
|
||||
extras[name] = value;
|
||||
} else {
|
||||
props[name] = value;
|
||||
@ -295,4 +311,22 @@ export class Props implements IPropParent {
|
||||
this.stash.purge();
|
||||
this.items.forEach(item => item.purge());
|
||||
}
|
||||
|
||||
getProp(path: string, stash = true): Prop | null {
|
||||
return this.query(path, stash as any) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个属性值
|
||||
*/
|
||||
getPropValue(path: string): any {
|
||||
return this.getProp(path, false)?.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置单个属性值
|
||||
*/
|
||||
setPropValue(path: string, value: any) {
|
||||
this.getProp(path, true)!.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
import { RootSchema } from '@ali/lowcode-globals';
|
||||
import { Node, NodeParent } from './node';
|
||||
import { DocumentModel } from '../document-model';
|
||||
import { NodeChildren } from './node-children';
|
||||
|
||||
/**
|
||||
* 根容器节点
|
||||
*
|
||||
* [Node Properties]
|
||||
* componentName: Page/Block/Component
|
||||
* props
|
||||
* children
|
||||
*
|
||||
* [Root Container Extra Properties]
|
||||
* fileName
|
||||
* meta
|
||||
* state
|
||||
* defaultProps
|
||||
* dataSource
|
||||
* lifeCycles
|
||||
* methods
|
||||
* css
|
||||
*
|
||||
* [Directives **not used**]
|
||||
* loop
|
||||
* loopArgs
|
||||
* condition
|
||||
* ------- future support -----
|
||||
* conditionGroup
|
||||
* title
|
||||
* ignore
|
||||
* locked
|
||||
* hidden
|
||||
*/
|
||||
export class RootNode extends Node implements NodeParent {
|
||||
readonly isRootNode = true;
|
||||
get isNodeParent() {
|
||||
return true;
|
||||
}
|
||||
get index() {
|
||||
return 0;
|
||||
}
|
||||
get nextSibling() {
|
||||
return null;
|
||||
}
|
||||
get prevSibling() {
|
||||
return null;
|
||||
}
|
||||
get zLevel() {
|
||||
return 0;
|
||||
}
|
||||
get parent() {
|
||||
return null;
|
||||
}
|
||||
get children(): NodeChildren {
|
||||
return this._children as NodeChildren;
|
||||
}
|
||||
internalSetParent(parent: null) {
|
||||
// empty
|
||||
}
|
||||
|
||||
constructor(readonly document: DocumentModel, rootSchema: RootSchema) {
|
||||
super(document, rootSchema);
|
||||
}
|
||||
|
||||
isPage() {
|
||||
return this.componentName === 'Page';
|
||||
}
|
||||
|
||||
isComponent() {
|
||||
return this.componentName === 'Component';
|
||||
}
|
||||
|
||||
isBlock() {
|
||||
return this.componentName === 'Block';
|
||||
}
|
||||
}
|
||||
|
||||
export function isRootNode(node: any): node is RootNode {
|
||||
return node && node.isRootNode;
|
||||
}
|
||||
1
packages/designer/src/document/node/transform-stage.ts
Normal file
1
packages/designer/src/document/node/transform-stage.ts
Normal file
@ -0,0 +1 @@
|
||||
export { TransformStage } from '@ali/lowcode-types';
|
||||
@ -1,5 +1,5 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { obx } from '@ali/lowcode-globals';
|
||||
import { obx } from '@ali/lowcode-editor-core';
|
||||
import { Node, comparePosition, PositionNO } from './node/node';
|
||||
import { DocumentModel } from './document-model';
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { SVGIcon, IconProps } from "@ali/lowcode-globals";
|
||||
import { SVGIcon, IconProps } from "@ali/lowcode-utils";
|
||||
|
||||
export function IconClone(props: IconProps) {
|
||||
return (
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { SVGIcon, IconProps } from "@ali/lowcode-globals";
|
||||
import { SVGIcon, IconProps } from "@ali/lowcode-utils";
|
||||
|
||||
export function IconComponent(props: IconProps) {
|
||||
return (
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { SVGIcon, IconProps } from "@ali/lowcode-globals";
|
||||
import { SVGIcon, IconProps } from "@ali/lowcode-utils";
|
||||
|
||||
export function IconContainer(props: IconProps) {
|
||||
return (
|
||||
|
||||
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