diff --git a/.eslintrc.js b/.eslintrc.js
index 5a8fe9e979..972882ce73 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -15,12 +15,11 @@ module.exports = {
'no-prototype-builtins': 1,
'no-useless-constructor': 1,
'no-empty-function': 1,
- '@typescript-eslint/member-ordering': 0,
'lines-between-class-members': 0,
'no-await-in-loop': 0,
'no-plusplus': 0,
'@typescript-eslint/no-parameter-properties': 0,
- '@typescript-eslint/no-unused-vars': 1,
+ 'no-restricted-exports': ['error'],
'no-multi-assign': 1,
'no-dupe-class-members': 1,
'react/no-deprecated': 1,
@@ -35,10 +34,26 @@ module.exports = {
'@typescript-eslint/indent': 0,
'import/no-cycle': 0,
'@typescript-eslint/no-shadow': 0,
- "@typescript-eslint/method-signature-style": 0,
- "@typescript-eslint/consistent-type-assertions": 0,
- "@typescript-eslint/no-useless-constructor": 0,
+ '@typescript-eslint/method-signature-style': 0,
+ '@typescript-eslint/consistent-type-assertions': 0,
+ '@typescript-eslint/no-useless-constructor': 0,
'@typescript-eslint/dot-notation': 0, // for lint performance
'@typescript-eslint/restrict-plus-operands': 0, // for lint performance
- }
+ 'no-unexpected-multiline': 1,
+ 'no-multiple-empty-lines': ['error', { max: 1 }],
+ 'lines-around-comment': ['error', {
+ beforeBlockComment: true,
+ afterBlockComment: false,
+ afterLineComment: false,
+ allowBlockStart: true,
+ }],
+ 'comma-dangle': ['error', 'always-multiline'],
+ '@typescript-eslint/member-ordering': [
+ 'error',
+ { default: ['signature', 'field', 'constructor', 'method'] }
+ ],
+ '@typescript-eslint/no-unused-vars': ['error'],
+ 'no-redeclare': 0,
+ '@typescript-eslint/no-redeclare': 1,
+ },
};
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index bc889c3079..670db7dfbd 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,13 +2,7 @@
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence
-* @leoyuan @JackLian
+* @liujuping @1ncounter
/modules/material-parser @akirakai
-/modules/code-generator @Clarence-pan
-
-/packages/renderer-core/ @liujuping
-/packages/react-renderer/ @liujuping
-/packages/react-simulator-renderer/ @liujuping
-/packages/rax-renderer/ @liujuping
-/packages/rax-simulator-renderer/ @liujuping
\ No newline at end of file
+/modules/code-generator @qingniaotonghua
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
index f2292f413e..c72471ee28 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -1,6 +1,6 @@
---
name: Bug report / 提交 bug
-about: Create a report to help us improve / 提交一个好的 bug 帮助我们优化引擎
+about: Create a report to help us improve / 提交一个好的 issue 帮助我们优化引擎,[引擎的 issue 说明](https://lowcode-engine.cn/site/community/issue)
title: ''
labels: ''
assignees: ''
diff --git a/.github/workflows/check base branch.yml b/.github/workflows/check base branch.yml
new file mode 100644
index 0000000000..cef996c75a
--- /dev/null
+++ b/.github/workflows/check base branch.yml
@@ -0,0 +1,33 @@
+name: Check Base Branch
+
+on:
+ pull_request:
+ types: [opened]
+
+jobs:
+ code-review:
+ name: Check
+ runs-on: ubuntu-latest
+
+ steps:
+ # 判断用户是否有写仓库权限
+ - name: 'Check User Permission'
+ uses: 'lannonbr/repo-permission-check-action@2.0.0'
+ with:
+ permission: 'write'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: 'Check base branch name is develop or not'
+ if: github.event.pull_request.base.ref != 'develop' # check the target branch if it's master
+ uses: actions-cool/issues-helper@v2
+ with:
+ actions: 'create-comment'
+ token: ${{ secrets.GITHUB_TOKEN }}
+ issue-number: ${{ github.event.pull_request.number }}
+ body: |
+ 感谢你的 PR,根据引擎的 [研发协作流程](https://lowcode-engine.cn/site/docs/participate/flow),请将目标合入分支设置为 **develop**。
+
+ Thanks in advance, according to the [Contribution Guideline](https://lowcode-engine.cn/site/docs/participate/flow), please set the base branch to **develop**.
+
+ @${{ github.event.pull_request.user.login }}
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..4636a1bdd1
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,116 @@
+name: Node CI
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ upload-designer-codecov:
+ runs-on: ubuntu-latest
+ # if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test designer
+ run: cd packages/designer && npm run test:cov && cd ../..
+
+ - name: Upload designer coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ # working-directory: packages/designer
+ directory: ./packages/designer/coverage
+ token: ${{ secrets.CODECOV_TOKEN }}
+ name: designer
+ fail_ci_if_error: true
+ verbose: true
+
+ upload-renderer-core:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test renderer-core
+ run: cd packages/renderer-core && npm run test:cov && cd ../..
+
+ - name: Upload renderer-core coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ # working-directory: packages/designer
+ directory: ./packages/renderer-core/coverage
+ token: ${{ secrets.CODECOV_TOKEN }}
+ name: renderer-core
+ fail_ci_if_error: true
+ verbose: true
+
+ upload-react-simulator-renderer:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test react-simulator-renderer
+ run: cd packages/react-simulator-renderer && npm run test:cov && cd ../..
+
+ - name: Upload react-simulator-renderer coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ # working-directory: packages/designer
+ directory: ./packages/react-simulator-renderer/coverage
+ token: ${{ secrets.CODECOV_TOKEN }}
+ name: react-simulator-renderer
+ fail_ci_if_error: true
+ verbose: true
+
+ upload-code-generator:
+ runs-on: ubuntu-latest
+ # if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test code-generator
+ run: cd modules/code-generator && npm i && npm run build && npm run test:cov && cd ../..
+
+ - name: Upload code-generator coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ # working-directory: packages/designer
+ directory: ./modules/code-generator/coverage
+ token: ${{ secrets.CODECOV_TOKEN }}
+ name: code-generator
+ fail_ci_if_error: true
+ verbose: true
\ No newline at end of file
diff --git a/.github/workflows/cov packages.yml b/.github/workflows/cov packages.yml
new file mode 100644
index 0000000000..7f92e1009c
--- /dev/null
+++ b/.github/workflows/cov packages.yml
@@ -0,0 +1,96 @@
+name: coverage
+
+on:
+ pull_request:
+ paths:
+ - 'packages/**'
+ - '!packages/**.md'
+
+jobs:
+ cov-designer:
+ runs-on: ubuntu-latest
+ # skip fork's PR, otherwise it fails while making a comment
+ if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - uses: ArtiomTr/jest-coverage-report-action@v2
+ with:
+ working-directory: packages/designer
+ test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json
+ package-manager: yarn
+ annotations: none
+
+ cov-renderer-core:
+ runs-on: ubuntu-latest
+ # skip fork's PR, otherwise it fails while making a comment
+ if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - uses: ArtiomTr/jest-coverage-report-action@v2
+ with:
+ working-directory: packages/renderer-core
+ test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json
+ package-manager: yarn
+ annotations: none
+
+ cov-react-simulator-renderer:
+ runs-on: ubuntu-latest
+ # skip fork's PR, otherwise it fails while making a comment
+ if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - uses: ArtiomTr/jest-coverage-report-action@v2
+ with:
+ working-directory: packages/react-simulator-renderer
+ test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json
+ package-manager: yarn
+ annotations: none
+
+ cov-utils:
+ runs-on: ubuntu-latest
+ # skip fork's PR, otherwise it fails while making a comment
+ if: ${{ github.event.pull_request.head.repo.full_name == 'alibaba/lowcode-engine' }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - uses: ArtiomTr/jest-coverage-report-action@v2
+ with:
+ working-directory: packages/utils
+ test-script: npm test -- --jest-ci --jest-json --jest-coverage --jest-testLocationInResults --jest-outputFile=report.json
+ package-manager: yarn
+ annotations: none
\ No newline at end of file
diff --git a/.github/workflows/help wanted.yml b/.github/workflows/help wanted.yml
index 94927ad28f..619d08b936 100644
--- a/.github/workflows/help wanted.yml
+++ b/.github/workflows/help wanted.yml
@@ -1,4 +1,4 @@
-name: Issue Reply
+name: Help Wanted
on:
issues:
diff --git a/.github/workflows/insufficient information.yml b/.github/workflows/insufficient information.yml
index 33c1d39067..c49e133f16 100644
--- a/.github/workflows/insufficient information.yml
+++ b/.github/workflows/insufficient information.yml
@@ -1,4 +1,4 @@
-name: Issue Reply
+name: Insufficient Info
on:
issues:
@@ -16,4 +16,4 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
- 你好 @${{ github.event.issue.user.login }},由于缺乏必要的信息(如 bug 重现步骤、引擎版本信息 等),无法定位问题,请按照 [issue bug 模板](https://github.com/alibaba/lowcode-engine/blob/main/.github/ISSUE_TEMPLATE/bug-report.md) 补全信息。
+ 你好 @${{ github.event.issue.user.login }},由于缺乏必要的信息(如 bug 重现步骤、引擎版本信息 等),无法定位问题,请按照 [issue bug 模板](https://github.com/alibaba/lowcode-engine/blob/main/.github/ISSUE_TEMPLATE/bug-report.md) 补全信息,也可以通过阅读 [引擎的 issue 说明](https://lowcode-engine.cn/site/community/issue) 了解什么类型的 issue 可以获得更好、更快的支持。
diff --git a/.github/workflows/pr comment by chatgpt.yml b/.github/workflows/pr comment by chatgpt.yml
new file mode 100644
index 0000000000..52585c4778
--- /dev/null
+++ b/.github/workflows/pr comment by chatgpt.yml
@@ -0,0 +1,23 @@
+name: Pull Request Review By ChatGPT
+
+on:
+ pull_request:
+ types: [opened, synchronize, reopened]
+
+jobs:
+ code-review:
+ name: Code Review
+ runs-on: ubuntu-latest
+
+ steps:
+ # 判断用户是否有写仓库权限
+ - name: 'Check User Permission'
+ uses: 'lannonbr/repo-permission-check-action@2.0.0'
+ with:
+ permission: 'write'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - uses: opensumi/actions/.github/actions/code-review@main
+ env:
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
\ No newline at end of file
diff --git a/.github/workflows/pre build.yml b/.github/workflows/pre build.yml
new file mode 100644
index 0000000000..e6f7d6479d
--- /dev/null
+++ b/.github/workflows/pre build.yml
@@ -0,0 +1,34 @@
+name: Pre Build
+
+on:
+ push:
+ paths:
+ - 'packages/**'
+ - '!packages/**.md'
+ pull_request:
+ paths:
+ - 'packages/**'
+ - '!packages/**.md'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ - name: Install dependencies and setup
+ run: npm install && npm run setup
+
+ - name: Build
+ run: npm run build
+
+ - name: Check build status
+ run: |
+ if [ $? -eq 0 ]; then
+ echo "Build succeeded!"
+ else
+ echo "Build failed!"
+ exit 1
+ fi
diff --git a/.github/workflows/publish docs.yml b/.github/workflows/publish docs.yml
new file mode 100644
index 0000000000..139b70239f
--- /dev/null
+++ b/.github/workflows/publish docs.yml
@@ -0,0 +1,53 @@
+name: Update and Publish Docs
+
+on:
+ push:
+ branches:
+ - develop
+ paths:
+ - 'docs/docs/**'
+ workflow_dispatch:
+
+jobs:
+ publish-docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Node.js
+ uses: actions/setup-node@v2
+ with:
+ ref: 'develop'
+ node-version: '16'
+ registry-url: 'https://registry.npmjs.org'
+ - run: cd docs && npm install
+ - run: |
+ cd docs
+ npm version patch
+ git config --local user.email "action@github.com"
+ git config --local user.name "GitHub Action"
+ git add package.json
+ git commit -m "chore(docs): publish documentation"
+ git push
+ - run: cd docs && npm run build && npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ - name: Get version
+ id: get_version
+ run: echo "version=$(node -p "require('./docs/package.json').version")" >> $GITHUB_OUTPUT
+
+ comment-pr:
+ needs: publish-docs
+ runs-on: ubuntu-latest
+ steps:
+ - name: Comment on PR
+ if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true
+ uses: actions/github-script@v4
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ github.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: '🚀 New version has been released: ' + '${{ needs.publish-docs.outputs.version }}'
+ })
diff --git a/.github/workflows/publish engine beta.yml b/.github/workflows/publish engine beta.yml
new file mode 100644
index 0000000000..ed4c374756
--- /dev/null
+++ b/.github/workflows/publish engine beta.yml
@@ -0,0 +1,30 @@
+name: Publish Engine Beta
+
+on:
+ push:
+ branches:
+ - 'release/[0-9]+.[0-9]+.[0-9]+-beta'
+ paths:
+ - 'packages/**'
+
+jobs:
+ publish-engine:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Node.js
+ uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+ registry-url: 'https://registry.npmjs.org'
+ - run: npm install && npm run setup
+ - run: |
+ npm run build
+ git config --local user.email "action@github.com"
+ git config --local user.name "GitHub Action"
+ - run: npm run pub:prerelease
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ - name: Get version
+ id: get_version
+ run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
diff --git a/.github/workflows/publish engine.yml b/.github/workflows/publish engine.yml
new file mode 100644
index 0000000000..ddbefcde55
--- /dev/null
+++ b/.github/workflows/publish engine.yml
@@ -0,0 +1,33 @@
+name: Publish Engine
+
+on:
+ workflow_dispatch:
+ inputs:
+ publishCommand:
+ description: 'publish command'
+ required: true
+
+jobs:
+ publish-engine:
+ runs-on: ubuntu-latest
+ if: >-
+ contains(github.ref, 'refs/heads/release/') &&
+ (github.actor == '1ncounter' || github.actor == 'liujuping')
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Node.js
+ uses: actions/setup-node@v2
+ with:
+ node-version: '16'
+ registry-url: 'https://registry.npmjs.org'
+ - run: npm install && npm run setup
+ - run: |
+ npm run build
+ git config --local user.email "action@github.com"
+ git config --local user.name "GitHub Action"
+ - run: npm run ${{ github.event.inputs.publishCommand }}
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ - name: Get version
+ id: get_version
+ run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index aa9b14b045..6fa710ec4d 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -14,9 +14,10 @@ jobs:
close-issue-message: 'This issue was closed because it has been stalled for 10 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.'
days-before-issue-stale: 10
- days-before-issue-close: 2
+ days-before-issue-close: 10
days-before-pr-stale: 10
- days-before-pr-close: 2
- exempt-issue-labels: 'bug,enhancement,good first issue,help wanted,WIP'
+ days-before-pr-close: 10
+ exempt-issue-labels: 'bug,enhancement,good first issue,help wanted,WIP,discussion,documentation,later,material'
stale-issue-label: 'stale'
- stale-pr-label: 'stale'
\ No newline at end of file
+ stale-pr-label: 'stale'
+ exempt-all-assignee: true
\ No newline at end of file
diff --git a/.github/workflows/test modules.yml b/.github/workflows/test modules.yml
index 9410626e88..b2464cc40c 100644
--- a/.github/workflows/test modules.yml
+++ b/.github/workflows/test modules.yml
@@ -1,4 +1,4 @@
-name: lint & test
+name: Lint & Test (Mods)
on:
push:
diff --git a/.github/workflows/test packages.yml b/.github/workflows/test packages.yml
index cc05742d54..45fa665465 100644
--- a/.github/workflows/test packages.yml
+++ b/.github/workflows/test packages.yml
@@ -1,4 +1,4 @@
-name: lint & test
+name: Lint & Test (Pkgs)
on:
push:
@@ -41,4 +41,100 @@ jobs:
run: npm i && npm run setup:skip-build
- name: test
- run: cd packages/designer && npm test
\ No newline at end of file
+ run: cd packages/designer && npm test
+
+ test-editor-skeleton:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test
+ run: cd packages/editor-skeleton && npm test
+
+ test-renderer-core:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test
+ run: cd packages/renderer-core && npm test
+
+ test-react-simulator-renderer:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test
+ run: cd packages/react-simulator-renderer && npm test
+
+ test-utils:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test
+ run: cd packages/utils && npm test
+
+ test-editor-core:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test
+ run: cd packages/editor-core && npm test
+
+ test-plugin-command:
+ runs-on: ubuntu-latest
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - uses: actions/setup-node@v2
+ with:
+ node-version: '14'
+
+ - name: install
+ run: npm i && npm run setup:skip-build
+
+ - name: test
+ run: cd packages/plugin-command && npm test
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2f87724cb9..6a19ae3e0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ packages/*/output/
packages/demo/
package-lock.json
yarn.lock
+pnpm-lock.yaml
deploy-space/packages
deploy-space/.env
@@ -36,6 +37,7 @@ lib-cov
# Coverage directory used by tools like istanbul
coverage
+coverage-all
# nyc test coverage
.nyc_output
@@ -106,3 +108,5 @@ typings/
# codealike
codealike.json
.node
+
+.must.config.js
\ No newline at end of file
diff --git a/CONTRIBUTOR.md b/CONTRIBUTOR.md
index c15f58af95..11d50baade 100644
--- a/CONTRIBUTOR.md
+++ b/CONTRIBUTOR.md
@@ -16,6 +16,7 @@
- [leoyuan](https://github.com/leoyuan)
- [liujuping](https://github.com/liujuping)
- [lqy978599280](https://github.com/lqy978599280)
+- [markyun](https://github.com/markyun)
- [mark-ck](https://github.com/mark-ck)
- [mochen666](https://github.com/mochen666)
- [tsy77](https://github.com/tsy77)
@@ -23,5 +24,6 @@
- [Ychangqing](https://github.com/Ychangqing)
- [yize](https://github.com/yize)
- [youluna](https://github.com/youluna)
+- [ibreathebsb](https://github.com/ibreathebsb)
如果您贡献过低代码引擎,但是没有看到您的名字,为我们的疏忽感到抱歉。欢迎您通过 PR 补充上自己的名字。
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000000..a089167a78
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: [
+ ['@babel/plugin-proposal-decorators', { legacy: true }],
+ [require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }],
+ ],
+};
\ No newline at end of file
diff --git a/deploy-space/static/index.html b/deploy-space/static/index.html
index 3b4cbddc29..e7ff4ba730 100644
--- a/deploy-space/static/index.html
+++ b/deploy-space/static/index.html
@@ -21,7 +21,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+> 注:如果 unpkg 的服务比较缓慢,您可以使用官方 CDN 来获得确定版本的低代码引擎,如对于引擎的 1.0.18 版本,可用以下官方 CDN 替代
+> - [https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js](https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/1.0.18/dist/js/engine-core.js)
+
+
+### 配置打包
+
+因为这些资源已经通过 UMD 方式引入,所以在 webpack 等构建工具中需要配置它们为 external,不再重复打包:
+
+```javascript
+{
+ "externals": {
+ "react": "var window.React",
+ "react-dom": "var window.ReactDOM",
+ "prop-types": "var window.PropTypes",
+ "@alifd/next": "var window.Next",
+ "@alilc/lowcode-engine": "var window.AliLowCodeEngine",
+ "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
+ "moment": "var window.moment",
+ "lodash": "var window._"
+ }
+}
+```
+
+### 初始化低代码编辑器
+
+正确引入后,我们可以直接通过 window 上的变量进行引用,如 `window.AliLowCodeEngine.init`。您可以直接通过此方式初始化低代码引擎:
+
+```javascript
+// 确保在执行此命令前,在
中已有一个 id 为 lce-container 的
+window.AliLowCodeEngine.init(document.getElementById('lce-container'), {
+ enableCondition: true,
+ enableCanvasLock: true,
+});
+```
+
+如果您的项目中使用了 TypeScript,您可以通过如下 devDependencies 引入相关包,并获得对应的类型推断。
+```javascript
+// package.json
+{
+ "devDependencies": {
+ "@alilc/lowcode-engine": "^1.0.0"
+ }
+}
+```
+```javascript
+// src/index.tsx
+import { init } from '@alilc/lowcode-engine';
+
+init(document.getElementById('lce-container'), {
+ enableCondition: true,
+ enableCanvasLock: true,
+});
+```
+
+init 的功能包括但不限于:
+
+1. 传递 options 并设置 config 对象;
+2. 传递 preference 并设置 plugins 入参;
+3. 初始化 Workbench;
+
+> 本节中的低代码编辑器例子可以在 demo 中找到:[https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/index.ts](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/index.ts)
+
+## 配置低代码编辑器
+详见[低代码扩展简述](/site/docs/guide/expand/editor/summary)章节。
diff --git a/docs/docs/guide/create/useRenderer.md b/docs/docs/guide/create/useRenderer.md
new file mode 100644
index 0000000000..a9fc79909e
--- /dev/null
+++ b/docs/docs/guide/create/useRenderer.md
@@ -0,0 +1,106 @@
+---
+title: 接入运行时
+sidebar_position: 1
+---
+
+低代码引擎的编辑器将产出两份数据:
+
+- 资产包数据 assets:包含物料名称、包名及其获取方式,对应协议中的[《低代码引擎资产包协议规范》](/site/docs/specs/assets-spec)
+- 页面数据 schema:包含页面结构信息、生命周期和代码信息,对应协议中的[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)
+
+经过上述两份数据,可以直接交由渲染模块或者出码模块来运行,二者的区别在于:
+
+- 渲染模块:使用资产包数据、页面数据和低代码运行时,并且允许维护者在低代码编辑器中用 `低代码(LowCode)`的方式继续维护;
+- 出码模块:不依赖低代码运行时和页面数据,直接生成可直接运行的代码,并且允许维护者用 `源码(ProCode)` 的方式继续维护,但无法再利用低代码编辑器;
+
+> 渲染和出码的详细阐述可参考此文:[低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ)
+
+## 渲染模块
+
+[在 Demo 中](https://lowcode-engine.cn/demo/demo-general/index.html),右上角有渲染模块的示例使用方式:
+
+
+基于官方提供的渲染模块 [@alifd/lowcode-react-renderer](https://github.com/alibaba/lowcode-engine/tree/main/packages/react-renderer),你可以在 React 上下文渲染低代码编辑器产出的页面。
+
+### 构造渲染模块所需数据
+
+渲染模块所需要的数据需要通过编辑器产出的数据进行一定的转换,规则如下:
+
+- schema:从编辑器产出的 projectSchema 中拿到 componentsTree 中的首项,即 `projectSchema.componentsTree[0]`;
+- components:需要根据编辑器产出的资产包 assets 中,根据页面 projectSchema 中声明依赖的 componentsMap,来加载所有依赖的资产包,最后获取资产包的实例并生成物料 - 资产包的键值对 components。
+
+这个过程可以参考 demo 项目中的 `src/preview.tsx`:
+
+```typescript
+async function getSchemaAndComponents() {
+ const packages = JSON.parse(window.localStorage.getItem('packages') || '');
+ const projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || '');
+ const { componentsMap: componentsMapArray, componentsTree } = projectSchema;
+ const componentsMap: any = {};
+ componentsMapArray.forEach((component: any) => {
+ componentsMap[component.componentName] = component;
+ });
+ const schema = componentsTree[0];
+
+ const libraryMap = {};
+ const libraryAsset = [];
+ packages.forEach(({ package: _package, library, urls, renderUrls }) => {
+ libraryMap[_package] = library;
+ if (renderUrls) {
+ libraryAsset.push(renderUrls);
+ } else if (urls) {
+ libraryAsset.push(urls);
+ }
+ });
+
+ const vendors = [assetBundle(libraryAsset, AssetLevel.Library)];
+
+ const assetLoader = new AssetLoader();
+ await assetLoader.load(libraryAsset);
+ const components = await injectComponents(buildComponents(libraryMap, componentsMap));
+
+ return {
+ schema,
+ components,
+ };
+}
+```
+
+### 进行渲染
+
+拿到 schema 和 components 以后,您可以借由资产包数据和页面数据来完成页面的渲染:
+```tsx
+import React from 'react';
+import ReactRenderer from '@alilc/lowcode-react-renderer';
+
+const SamplePreview = () => {
+ return (
+
+ );
+}
+```
+
+> 注 1:您可以注意到,此处是依赖了 React 进行渲染的,对于 Vue 形态的渲染或编辑器支持,详见[对应公告](https://github.com/alibaba/lowcode-engine/issues/236)。
+>
+> 注 2:本节示例可在 Demo 代码里找到更完整的版本:[https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/preview.tsx](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/preview.tsx)
+
+
+## 出码模块
+
+[在 Demo 中](https://lowcode-engine.cn/demo/demo-general/index.html),右上角有出码模块的示例使用方式:
+
+
+
+> 本节示例可在出码插件里找到:[https://github.com/alibaba/lowcode-code-generator-demo](https://github.com/alibaba/lowcode-code-generator-demo)
+
+
+## 低代码的生产和消费流程总览
+
+经过“接入编辑器” - “接入运行时”这两节的介绍,我们已经可以了解到低代码所构建的生产和消费流程了,梳理如下图:
+
+
+
+如上述流程所示,您一般需要一个后端项目来保存页面数据信息,如果资产包信息是动态的,也需要保存资产包信息。
diff --git a/docs/docs/guide/design/_category_.json b/docs/docs/guide/design/_category_.json
new file mode 100644
index 0000000000..1868732be3
--- /dev/null
+++ b/docs/docs/guide/design/_category_.json
@@ -0,0 +1,6 @@
+{
+ "label": "引擎设计原理",
+ "position": 3,
+ "collapsed": false,
+ "collapsible": true
+}
diff --git a/docs/docs/guide/design/datasourceEngine.md b/docs/docs/guide/design/datasourceEngine.md
new file mode 100644
index 0000000000..33c7adb082
--- /dev/null
+++ b/docs/docs/guide/design/datasourceEngine.md
@@ -0,0 +1,152 @@
+---
+title: 数据源引擎设计
+sidebar_position: 7
+---
+## 核心原理
+
+考虑之后的扩展性和兼容性,核心分为了 2 类包,一个是 **datasource-engine** ,另一个是 **datasource-engine-x-handler** ,x 的意思其实是对应数据源的 type,比如说 **datasource-engine-mtop-handler**,也就是说我们会将真正的请求工具放在 handler 里面去处理,engine 在使用的时候由使用方自身来决定需要注册哪些 handler,这样的目的有 2 个,一个是如果将所有的 handler 都放到一个包,对于端上来说这个包过大,有一些浪费资源和损耗性能的问题,另一个是如果有新的类型的数据源出现,只需要按照既定的格式去新增一个对应的 handler 处理器即可,达到了高扩展性的目的;
+
+
+
+### DataSourceEngine
+
+- engine:engine 主要分 2 类,一类是面向 render 引擎的,可以从 engine/interpret 引入,一类是面向出码或者说直接单纯使用数据源引擎的场景,可以从 engine/runtime 引入,代码如下
+
+```typescript
+import { createInterpret, createRuntime } from '@alilc/lowcode-datasource-engine';
+```
+
+create 方法定义如下
+
+```typescript
+interface IDataSourceEngineFactory {
+ create(dataSource: DataSource, context: Omit, extraConfig?: {
+ requestHandlersMap: RequestHandlersMap;
+ [key: string]: any;
+ }): IDataSourceEngine;
+}
+```
+
+create 接收三个参数,第一个是 DataSource,对于运行时渲染和出码来说,DataSource 的定义分别如下:
+
+```typescript
+/**
+ * 数据源对象--运行时渲染
+ */
+export interface DataSource {
+ list: DataSourceConfig[];
+ dataHandler?: JSFunction;
+}
+
+/**
+ * 数据源对象
+ */
+export interface DataSourceConfig {
+ id: string;
+ isInit: boolean | JSExpression;
+ type: string;
+ requestHandler?: JSFunction;
+ dataHandler?: JSFunction;
+ options?: {
+ uri: string | JSExpression;
+ params?: JSONObject | JSExpression;
+ method?: string | JSExpression;
+ isCors?: boolean | JSExpression;
+ timeout?: number | JSExpression;
+ headers?: JSONObject | JSExpression;
+ [option: string]: CompositeValue;
+ };
+ [otherKey: string]: CompositeValue;
+}
+```
+
+但是对于出码来说,create 和 DataSource 定义如下:
+
+```typescript
+export interface IRuntimeDataSourceEngineFactory {
+ create(dataSource: RuntimeDataSource, context: Omit, extraConfig?: {
+ requestHandlersMap: RequestHandlersMap;
+ [key: string]: any;
+ }): IDataSourceEngine;
+}
+
+export interface RuntimeOptionsConfig {
+ uri: string;
+ params?: Record;
+ method?: string;
+ isCors?: boolean;
+ timeout?: number;
+ headers?: Record;
+ shouldFetch?: () => boolean;
+ [option: string]: unknown;
+}
+export declare type RuntimeOptions = () => RuntimeOptionsConfig; // 考虑需要动态获取值的情况,这里在运行时会真正的转为一个 function
+
+export interface RuntimeDataSourceConfig {
+ id: string;
+ isInit: boolean;
+ type: string;
+ requestHandler?: () => {};
+ dataHandler: (data: unknown, err?: Error) => {};
+ options?: RuntimeOptions;
+ [otherKey: string]: unknown;
+}
+
+/**
+ * 数据源对象
+ */
+export interface RuntimeDataSource {
+ list: RuntimeDataSourceConfig[];
+ dataHandler?: (dataMap: DataSourceMap) => void;
+}
+```
+
+2 者的区别还是比较明显的,一个是带 js 表达式一类的字符串,另一个是真正转为直接可以运行的 js 代码,对于出码来说,转为可执行的 js 代码的过程是出码自身负责的,对于渲染引擎来说,它只能接受到初始的 schema json 所以需要数据源引擎来做转化
+
+- context:数据源引擎内部有一些使用了 this 的表达式,这些表达式需要求值的时候依赖上下文,因此需要将当前的上下文丢给数据源引擎,另外在 handler 里面去赋值的时候,也会用到诸如 setState 这种上下文里面的 api,当然,这个是可选的,我们后面再说。
+
+```typescript
+/**
+ * 运行时上下文--暂时是参考 react,当然可以自己构建,完全没问题
+ */
+export interface IRuntimeContext> {
+ /** 当前容器的状态 */
+ readonly state: TState;
+ /** 设置状态 (浅合并) */
+ setState(state: Partial): void;
+ /** 自定义的方法 */
+ [customMethod: string]: any;
+ /** 数据源,key 是数据源的 ID */
+ dataSourceMap: Record;
+ /** 重新加载所有的数据源 */
+ reloadDataSource(): Promise;
+ /** 页面容器 */
+ readonly page: IRuntimeContext & {
+ readonly props: Record;
+ };
+ /** 低代码业务组件容器 */
+ readonly component: IRuntimeContext & {
+ readonly props: Record;
+ };
+}
+```
+
+- extraConfig:这个字段是为了留着扩展用的,除了一个必填的字段 **requestHandlersMap**
+
+```typescript
+export declare type RequestHandler = (ds: RuntimeDataSourceConfig, context: IRuntimeContext) => Promise>;
+export declare type RequestHandlersMap = Record;
+```
+
+RequestHandlersMap 是一个把数据源以及对应的数据源 handler 关联起来的桥梁,它的 key 对应的是数据源 DataSourceConfig 的 type,比如 mtop/http/jsonp ... ,每个类型的数据源在真正使用的时候会调用对应的 type-handler,并将当前的参数和上下文带给对应的 handler。
+
+create 调用结束后,可以获取到一个 DataSourceEngine 实例
+
+```typescript
+export interface IDataSourceEngine {
+ /** 数据源,key 是数据源的 ID */
+ dataSourceMap: Record;
+ /** 重新加载所有的数据源 */
+ reloadDataSource(): Promise;
+}
+```
diff --git a/docs/docs/guide/design/editor.md b/docs/docs/guide/design/editor.md
new file mode 100644
index 0000000000..0614d9c332
--- /dev/null
+++ b/docs/docs/guide/design/editor.md
@@ -0,0 +1,368 @@
+---
+title: 编排模块设计
+sidebar_position: 3
+---
+本篇重点介绍如何从零开始设计编排模块,设计思路是什么?思考编排的本质是什么?围绕着本质,如何设计并实现对应的功能模块。
+
+
+
+## 编排是什么
+
+所谓编排,即将设计器中的所有物料,进行布局设置、组件设置、交互设置(JS 编写/逻辑编排)后,形成符合业务诉求的 schema 描述。
+## 编排的本质
+
+首先,思考编排的本质是什么?
+
+编排的本质是生产符合《阿里巴巴中后台前端搭建协议规范》的数据**,**在这个场景里,协议是通过 JSON 来承载的。如:
+
+```json
+{
+ "componentName": "Page",
+ "props": {
+ "layout": "wide"
+ },
+ "children": [
+ {
+ "componentName": "Button",
+ "props": {
+ "size": "large"
+ }
+ }
+ ]
+}
+```
+
+可是在真实场景,节点数可能有成百上千,每个节点都具有新增、删除、修改、移动、插入子节点等操作,同时还有若干约束,JSON 结构操作起来不是很便利,于是我们仿 DOM 设计了 **节点模型 & 属性模型,**用更具可编程性的方式来编排,这是**编排系统的基石**。
+
+其次,每次编排动作后(CRUD),都需要实时的渲染出视图。广义的视图应该包括各种平台上的展现,浏览器、Rax、小程序、Flutter 等等,所以使用何种渲染器去渲染 JSON 结构应该可以由用户去扩展,我们定义一种机制去衔接设计态和渲染态。
+
+至此,我们已经完成了**编排模块最基础的功能**,接下来,就是完善细节,逐步丰满功能。比如:
+1. 编排面板的整体功能区划分设计;
+2. 节点属性设计;节点删除、移动等操作设计;容器节点设计;
+3. 节点拖拽功能、拖拽定位设计和实现;
+4. 节点在画布上的辅助功能,比如 hover、选中、选中时的操作项、resize、拖拽占位符等;
+5. 设计态和渲染态的坐标系转换,滚动监听等;
+6. 快捷键机制;
+7. 历史功能,撤销和重做;
+8. 结构化的插件扩展机制;
+9. 原地编辑功能;
+
+有非常多模块,但只要记住一点,这些功能的目的都是辅助用户在画布上有更好的编排体验、扩展能力而逐个增加设计的。
+
+## 编排功能模块
+### 模型设计
+
+编排实际上操作 schema,但是实际代码运行的过程中,我们将 schema 分成了很多层,每一层有各自的职责,他们所负责的功能是明确清晰的。这就是低代码引擎中的模型设计。
+
+我们通过将 schema 和常用的操作等结合起来,最终将低代码引擎的模型分为节点模型、属性模型、文档模型和项目模型。
+
+#### 项目模型(`Project`)
+
+项目模型提供项目管理能力。通常一个引擎启动会默认创建一个 `Project` 实例,有且只有一个。项目模型实例下可以持有多个文档模型的实例,而当前处于设计器设计状态的文档模型,我们将其添加 active 标识,也将其称为 `currentDocument`,可以通过 `project.currentDocument` 获得。
+
+一个 `Project` 包含若干个 `DocumentModel` 实例,即项目模型和文档模型的关系是 1 对 n,如下图所示:
+
+
+
+#### 文档模型(`DocumentModel`)
+
+文档模型提供文档管理的能力,每一个页面即一个文档流,对应一个文档模型。文档模型包含了一组 Node 组成的一颗树,类似于 DOM。我们可以通过文档模型来操作 `Node` 树,来达到管理文档模型的能力。每一个文档模型对应多个 `Node`,但是根 `Node` 只有一个,即 `rootNode` 和 `nodes`。
+
+文档模型可以通过 `Node` 树,通过 `doc.schema` 来导出文档的 `schema`,并使用其进行渲染。
+
+他们的关系如下图:
+
+
+
+#### 节点模型(`Node`)
+
+我们先看一下一个 `Node` 在 `schema` 中对应的示例:
+
+```javascript
+{
+ componentName: 'Text',
+ id: 'node_k1ow3cbf',
+ props: {
+ showTitle: false,
+ behavior: 'NORMAL',
+ content: {
+ use: 'zh_CN',
+ en_US: 'Title',
+ zh_CN: '个人信息',
+ type: 'i18n',
+ },
+ fieldId: 'text_k1ow3h1j',
+ maxLine: 0,
+ },
+ condition: true,
+}
+```
+
+上面的示例是一个 `Text` 的 `Node` 节点,而我们的 `Node` 节点模型就是负责这一层级的 `Schema` 管理。它的功能聚焦于单层级的 schema 相关操作。我们可以看一下节点模型的一些方法,了解其功能。
+
+```typescript
+declare class Node {
+ // Props
+ props: Props;
+ get propsData(): PropsMap | PropsList | null;
+ getProp(path: string, stash?: boolean): Prop | null;
+ getPropValue(path: string): any;
+ setPropValue(path: string, value: any): void;
+ clearPropValue(path: string): void;
+ mergeProps(props: PropsMap): void;
+ setProps(props?: PropsMap | PropsList | Props | null): void;
+
+ // Node
+ get parent(): ParentalNode | null;
+ get children(): NodeChildren | null;
+ get nextSibling(): Node | null;
+ get prevSibling(): Node | null;
+ remove(useMutator?: boolean, purge?: boolean): void;
+ select(): void;
+ hover(flag?: boolean): void;
+ replaceChild(node: Node, data: any): Node;
+ mergeChildren(remover: () => any, adder: (children: Node[]) => NodeData[] | null, sorter: () => any): void;
+ removeChild(node: Node): void;
+ insert(node: Node, ref?: Node, useMutator?: boolean): void;
+ insertBefore(node: any, ref?: Node, useMutator?: boolean): void;
+ insertAfter(node: any, ref?: Node, useMutator?: boolean): void;
+
+ // Schema
+ get schema(): Schema;
+ set schema(data: Schema);
+ export(stage?: TransformStage): Schema;
+ replaceWith(schema: Schema, migrate?: boolean): any;
+}
+```
+
+这里没有展示全部的方法,但是我们可以发现,`Node` 节点模型核心功能点有三个:
+
+1. `Props` 管理:通过 `Props` 实例管理所有的 `Prop`,包括新增、设置、删除等 `Prop` 相关操作。
+2. `Node` 管理:管理 `Node` 树的关系,修改当前 `Node` 节点或者 `Node` 子节点等。
+3. `Schema` 管理:可以通过 `Node` 获取当前层级的 `Schema` 描述协议内容,并且也可以修改它。
+
+通过 `Node` 这一层级,对 `Props`、`Node` 树和 `Schema` 的管理粒度控制到最低,这样扩展性也就更强。
+
+#### 属性模型(Prop)
+
+一个 `Props` 对应多个 `Prop`,每一个 `Prop` 对应 schema 的 `props` 下的一个字段。
+
+`Props` 管理的是 `Node` 节点模型中的 `props` 字段下的内容。而 `Prop` 管理的是 `props` 下的每一个 `key` 的内容,例如下面的示例中,一个 `Props` 管理至少 6 个 `Prop`,而其中一个 `Prop` 管理的是 `showTitle` 的结果。
+
+```javascript
+{
+ props: {
+ showTitle: false,
+ behavior: 'NORMAL',
+ content: {
+ use: 'zh_CN',
+ en_US: 'Title',
+ zh_CN: '个人信息',
+ type: 'i18n',
+ },
+ fieldId: 'text_k1ow3h1j',
+ maxLine: 0,
+ },
+}
+```
+#### 组件描述模型(ComponentMeta)
+
+编排已经等价于直接操作节点 & 属性了,而一个节点和一组对应的属性相当于一个真实的组件,而真实的组件一定是有约束的,比如组件名、组件类型、支持哪些属性以及属性类型、组件能否拖动、支持哪些扩展操作、组件是否是容器型组件、A 组件中能否放入 B 组件等等。
+
+于是,我们设计了一份协议专门负责组件描述,即《中后台搭建组件描述协议》,而编排模块中也有负责解析和使用符合描述协议规范的模块。
+
+每一个组件对应一个 `ComponentMeta` 的实例,其属性和方法就是描述协议中的所有字段,所有 `ComponentMeta` 都由设计器器的 `designer` 模块进行创建和管理,其他模块通过 `designer` 来获取指定的 `ComponentMeta` 实例,尤其是每个 `Node` 实例上都会挂载对应的 `ComponentMeta` 实例。
+
+
+
+组件描述模型是后续编排辅助的基础,包括设置面板、拖拽定位机制等。
+#### 项目、文档、节点和属性模型关系
+
+整体来看,一个 Project 包含若干个 DocumentModel 实例,每个 DocumentModel 包含一组 Node 构成一颗树(类似 DOM 树),每个 Node 通过 Props 实例管理所有 Prop。整体的关系图如下。
+
+
+
+节点 & 属性模型是引擎基石,几乎贯穿所有模块,相信从上面的类图已经能看出几个基础类的职责以及依赖关系。
+
+节点 & 属性模型等价于 JSON 数据结构,而编排的本质是产出 JSON 数据结构,现在可以重新表述为编排的本质是操作节点 & 属性模型了。
+
+```typescript
+// 一段编排的示例代码
+rootNode.insertAfter({ componentName: 'Button', props: { size: 'medium' } });
+rootNode.insertAfter({ componentName: 'Button', props: { size: 'medium' } });
+rootNode.children.get(1).getProp('size').setValue('large');
+rootNode.children.get(2).remove();
+rootNode.export();
+// => 产出 schema
+```
+
+### 画布渲染
+
+画布渲染使用了设计态与渲染态的双层架构。
+
+
+
+如上图,设计器和渲染器其实处在不同的 Frame 下,渲染器以单独的 `iframe` 嵌入。这样做的好处,一是为了给渲染器一个更纯净的运行环境,更贴近生产环境,二是扩展性考虑,让用户基于接口约束自定义自己的渲染器。
+
+#### xxx-renderer
+
+xxx-renderer 是一个纯 renderer,即一个渲染器,通过给定输入 schema、依赖组件和配置参数之后完成渲染。
+
+#### xxx-simulator-renderer
+
+xxx-simulator-renderer 通过和 host 进行通信来和设计器打交道,提供了 `DocumentModel` 获取 schema 和组件。将其传入 xxx-renderer 来完成渲染。
+
+另外其提供了一些必要的接口,来帮助设计器完成交互,比如点击渲染画布任意一个位置,需要能计算出点击的组件实例,继而找到设计器对应的 Node 实例,以及组件实例的位置/尺寸信息,让设计器完成辅助 UI 的绘制,如节点选中。
+
+#### react-simulator-renderer
+
+以官方提供的 react-simulator-renderer 为例,我们看一下点击一个 DOM 节点后编排模块是如何处理的。
+
+首先在初始化的时候,renderer 渲染的时候会给每一个元素添加 ref,通过 ref 机制在组件创建时将其存储起来。在存储的时候我们给实例添加 `Symbol('_LCNodeId')` 的属性。
+
+当点击之后,会去根据 `__reactInternalInstance$` 查找相应的 fiberNode,通过递归查找到对应的 React 组件实例。找到一个挂载着 `Symbol('_LCNodeId')` 的实例,也就是上面我们初始化添加的属性。
+
+通过 `Symbol('_LCNodeId')` 属性,我们可以获取 Node 的 id,这样我们就可以找到 Node 实例。
+
+通过 `getBoundingClientRect` 我们可以获取到 Node 渲染出来的 DOM 的相关信息,包括 `x`、`y`、`width`、`height` 等。
+
+通过 DOM 信息,我们将 focus 节点所需的标志渲染到对应的地方。hover、拖拽占位符、resize handler 等辅助 UI 都是类似逻辑。
+
+#### 通信机制
+
+既然设计器和渲染器处于两个 Frame,它们之间的事件通信、方法调用是通过各自的代理对象进行的,不允许其他方式,避免代码耦合。
+
+
+
+##### host
+host 可以访问设计器的所有模块,由于 renderer 层不负责与设计器相关的交互。所以增加了一层 host,作为通信的中间层。host 可以访问到设计器中所有模块,并提供相关方法供 simulator-renderer 层调用。例如 schema 的获取、组件获取等。
+
+simulator-renderer 通过调用 host 的方法,将 schema、components 等参数传给 renderer,让 renderer 进行渲染。
+
+##### xxx-simulator-renderer
+
+为了完成双向交互,simulator-renderer 也需要提供一些方法来供 host 层调用,之后当设计器和用户有交互,例如上述提到的节点选中。这里需要提供的方法有:
+
+- getClientRects
+- getClosestNodeInstance
+- findDOMNodes
+- getComponent
+- setNativeSelection
+- setDraggingState
+- setCopyState
+- clearState
+
+这样,host 和 simulator-renderer 之间便通过相关方法实现了双向通信,能在隔离设计器的基础上完成设计器到画布和画布到设计器的通信流程。
+
+### 编排辅助的核心
+#### 设置面板与设置器
+当在渲染画布上点击一个 DOM 节点,我们可以通过 xxx-simulator-renderer 获取 `Node` 节点,我们在 `Node` 上挂载了 `ComponentMeta` 实例。通过 `ComponentMeta` 我们获取到当前组件的描述模型。通过描述模型,我们即可获得组件、即当前 Node 支持的所有属性配置。
+
+
+
+##### 设置面板
+
+设置面板对于配置项的呈现结构是通过 `ComponentMeta.configure` 来确定的。
+
+```json
+{
+ "component": {
+ "isContainer": true
+ },
+ "props": {
+ "isExtends": true,
+ "override": [
+ {
+ "name": "count",
+ "title": {
+ "label": "展示的数字",
+ "tip": "count|大于 overflowCount 时显示为 ${overflowCount}+,为 0 时默认隐藏",
+ "docUrl": "https://fusion.alibaba-inc.com/pc/component/basic/badge"
+ },
+ "setter": {
+ "componentName": "MixedSetter",
+ "props": {
+ "setters": [
+ "StringSetter",
+ "ExpressionSetter"
+ ]
+ }
+ }
+ }
+ ]
+ }
+}
+```
+
+上述的 `component.isContainer` 描述了这个组件是否是一个容器组件。而 props 下的属性就是我们在设置面板中展示的属性,包含了这个属性的名称、使用的设置器、配置之后影响的是哪个属性等。
+
+而这只是描述,编排模块的 `SettingTopEntry` 便是管理设置面板的实现模块。
+
+`SettingTopEntry` 包含了 n 个 `SettingField`,每一个 `SettingField` 就对应下面要将的设置器。即 `SettingTopEntry` 负责管理多个 `SettingField`。
+
+##### 设置器
+选中节点可供配置的属性都有相应的设置器配置,比如文本、数字、颜色、JSON、Choice、I18N、表达式 等等,或者混合多种。
+
+设置器本质上是一个 React 组件,但是设置面板在渲染时会传入当前配置项对应的 `SettingField` 实例,`SettingField` 本质上就是包裹了 `Prop` 实例,设置器内部的行为以及 UI 变化都由设置器自己把控,但当属性值发生变化时需要通过 `SettingField` 下的 `Prop` 来修改值,因为修改 `Prop` 实例就相当于修改了 schema。一方面这样的设置器设置之后,保存的 schema 才是正确的,另外一方面,只有 schema 变化了,才能触发渲染画布重新渲染。
+
+#### 拖拽引擎 & 拖拽定位机制
+
+
+
+拖拽引擎(`Dragon`)核心完成的工作是将被拖拽对象拖拽到目标位置,涉及到几个概念:
+
+- 被拖拽对象 - `DragObject`
+- 拖拽到的目标位置 - `DropLocation`
+- 拖拽感应区 - `IPublicModelSensor`
+- 定位事件 - `LocateEvent`
+
+##### Sensor
+
+在引擎初始化的时候,我们监听 `document` 和 iframe `contentDocument` 的 `mouse`、`keyboard`、`drag` 事件来感知拖拽的发生。而这些监听的区域我们又称为拖拽感应区,也就是 `Sensor`。`Sensor` 会有多个,因为感应器有多个,默认设置器和设置面板是没有 `Sensor`,但是他们是可以注册 `Sensor` 来增加感应区域,例如大纲树就注册了自己的 `Sensor`。
+
+`Sensor` 有两个关键职责:
+1. 用于事件对象转换,比如坐标系换算。
+2. 根据拖拽过程中提供的位置信息,结合每一层 `Node` 也就是组件包含的描述信息,知道其是否能作为容器等限制条件,来进行进一步的定位,最后计算出精准信息来进行视图渲染。
+
+**拖拽流程**
+1. 在引擎初始化的时候,初始化多个 `Sensor`。
+2. 当拖拽开始的时候,开启 `mousemove`、`mouseleave`、`mouseover` 等事件的监听。
+3. 拖拽过程中根据 `mousemove` 的 `MouseEvent` 对象封装出 `LocateEvent` 对象,继而交给相应 `sensor` 做进一步定位处理。
+4. 拖拽结束时,根据拖拽的结果进行 schema 变更和视图渲染。
+5. 最后关闭拖拽开始时的事件监听。
+
+##### 拖拽方式
+根据拖拽的对象不同,我们将拖拽分为几种方式:
+1. **画布内拖拽:**此时 sensor 是 simulatorHost,拖拽完成之后,会根据拖拽的位置来完成节点的精确插入。
+2. **从组件面板拖拽到画布**:此时的 sensor 还是 simulatorHost,因为拖拽结束的目标还是画布。
+3. **大纲树面板拖拽到画布中**:此时有两个 sensor,一个是大纲树,当我们拖拽到画布区域时,画布区域内的 simulatorHost 开始接管。
+4. **画布拖拽到大纲树中**:从画布中开始拖拽时,最新生效的是 simulatorHost,当离开画布到大纲树时,大纲树 sensor 开始接管生效。当拖拽到大纲树的某一个节点下时,大纲树会将大纲树中的信息转化为 schema,然后渲染到画布中。
+### 其他
+
+引擎的编排能力远远不止上述所描述的功能,这里只描述了其核心和关键的功能。在整个引擎的迭代和设计过程中还有很多细节来使我们的引擎更好用、更容易扩展。
+
+#### schema 处理的管道机制
+
+通过 PropsReducer 的管道机制,用户可以定制自己需要的逻辑,来修改 Schema。
+
+#### 组件 metadata 处理的管道机制
+
+组件的描述信息都收拢在各自的 ComponentMeta 实例内,涉及到的消费方几乎遍及整个编排过程,包括但不限于 组件拖拽、拖拽辅助 UI、设置区、原地编辑、大纲树 等等。
+
+在用户需要自定义的场景,开放 ComponentMeta 的修改能力至关重要,因此我们设计了 metadata 初始化/修改的管道机制。
+
+#### hotkey & builtin-hotkey
+
+快捷键的实现,以及引擎内核默认绑定的快捷键行为。
+
+#### drag resize 引擎
+
+对于布局等类型的组件,支持拖拽改变大小。resize 拖拽引擎根据组件 ComponentMeta 声明来开启,拖拽后,触发组件的钩子函数(`onResizeStart` / `onResize` / `onResizeEnd`),完成 resize 过程。
+
+#### OffsetObserver
+
+设计态的辅助 UI 需要根据渲染态的视图变化而变化,比如渲染容器滚动了,此时通过 OffsetObserver 做一个动态的监听。
+
+#### 插件机制
+
+我们希望保持引擎内核足够小,但拥有足够强的扩展能力,所有扩展功能都通过插件机制来承载。
diff --git a/docs/docs/guide/design/generator.md b/docs/docs/guide/design/generator.md
new file mode 100644
index 0000000000..2310cb7a5f
--- /dev/null
+++ b/docs/docs/guide/design/generator.md
@@ -0,0 +1,118 @@
+---
+title: 出码模块设计
+sidebar_position: 5
+---
+
+本篇主要讲解了出码模块实现的基本思路与一些概念。如需接入出码和定制出码方案,可以参考《[使用出码功能](/site/docs/guide/expand/runtime/codeGeneration)》一节。
+
+## npm 包与仓库信息
+
+| **NPM 包** | **代码仓库** | **说明** |
+| --- | --- | --- |
+| [@alilc/lowcode-code-generator](https://www.npmjs.com/package/@alilc/lowcode-code-generator) | [alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine)(子目录:modules/code-generator)| 出码模块核心库,支持在 node 环境下运行,也提供了浏览器下运行的 standalone 模式 |
+| [@alilc/lowcode-plugin-code-generator](https://www.npmjs.com/package/@alilc/lowcode-plugin-code-generator) | [alibaba/lowcode-code-generator-demo](https://github.com/alibaba/lowcode-code-generator-demo) | 出码示例 -- 浏览器端出码插件 |
+
+## 出码模块原理
+
+出码模块的输入和输出很简单:
+
+
+这里有几个概念:
+
+- schema: 搭建协议内容,指符合《阿里巴巴中后台前端搭建协议规范》的 schema
+- solution:出码方案,指具体的项目框架(如 Rax,Ice.js)
+- Source Codes:生成的源代码,以目录树的形式进行描述
+
+可以看出,这是一个与用户基本没有交互,通过既定的流程完成整个功能链路的模块。其核心暴露的是一个将搭建协议 schema 按既定的 solution 转换为代码的函数。对于使用者来说就是一个输入输出都确定的黑盒系统。
+
+### 出码流程概述
+
+出码模块和编译器很类似,都是将代码的一种表现形式转换成另一种表现形式,如:
+
+#### 编译器流程
+
+
+#### 出码模块流程
+
+
+### 出码流程详解
+#### 协议解析
+
+协议解析主要是将输入的 schema 解析成更适合出码模块内部使用的数据结构的过程。这样在后面的代码生成过程中就可以直接用这些数据,不必重复解析了。
+
+
+
+主要步骤如下:
+
+- 解析三方组件依赖
+- 分析 ref API 的使用情况
+- 建立容器之间的依赖关系索引
+- 分析容器内的组件依赖关系
+- 分析路由配置
+- 分析 utils 和 NPM 包依赖关系
+- 其他兼容处理
+
+#### 前置优化
+
+前置优化是计划基于策略对 schema 做一些优化。
+
+主要逻辑分为分析、规则和优化三个部分,组合为一个支持通过配置进行一定程度定制化的策略包。每个策略包会先执行分析器,对输入进行特征提取,然后通过规则对特征进行判断,决定是否执行优化动作:
+
+
+
+#### 代码生成
+代码生成的流程如下:
+
+
+如果简单粗暴地拼字符串生成源代码将难以扩展和维护,因此出码模块在代码生成过程中将代码进行了一些抽象化。
+
+日常开发中,我们常常是基于某一个特定的项目框架,将一些配置、UI 代码、逻辑代码放到他们应该在的地方,最终形成一套可以 run 起来的业务系统。那么其实对于出码这件事,我们也可以层层拆解,**项目 -> 插槽 -> 模块 -> 文件 -> 代码块**(代码片段)。这样就能将复杂的项目产出问题,拆分为一个个相对专注且单一的代码块产出问题,同时也支持组合复用。
+
+
+
+注:中间表达结构即为对 Schema 解析后的结构化产物
+
+##### 插槽
+
+首先来看下插槽,插槽描述了对应模块在项目中相对路径,并且可以对模块做固定的命名。每个插槽都有一系列插件来完成代码产出工作。生成的一个或多个文件,最终会依照插槽的描述放入项目中。
+
+```typescript
+// 项目模版
+export interface IProjectTemplate {
+ slots: Record;
+}
+
+// 插槽
+interface IProjectSlot {
+ path: string[];
+ fileName?: string;
+}
+
+// 插槽出码插件配置
+interface IProjectPlugins {
+ [slotName: string]: BuilderComponentPlugin[];
+}
+```
+##### 代码块
+
+代码块是出码产物的最小单元,由出码模块插件产出,多个代码块最后会被组装为代码文件。每个代码块通过 name 描述自己,再通过 linkAfter 描述应该跟在哪些 name 的代码块后面。
+
+```typescript
+interface ICodeChunk {
+ type: ChunkType; // 处理类型 ast | string | json
+ fileType: string; // 文件类型 js | css | ts ...
+ name: string; // 代码块名称,与 linkAfter 相关
+ subModule?: string; // 模块内文件名,默认是 index
+ content: ChunkContent; // 代码块内容,数据格式与 type 相关
+ linkAfter: string[];
+}
+```
+
+#### 后置优化
+
+后置优化分为文件级别和项目级别两种:
+
+- 文件级别:在生成完一个文件后进行处理
+- 项目级别:在所有文件都生成完了之后进行处理
+
+文件级别的后置优化目前主要是有 prettier 这个代码格式化工具。
diff --git a/docs/docs/guide/design/materialParser.md b/docs/docs/guide/design/materialParser.md
new file mode 100644
index 0000000000..78936011fd
--- /dev/null
+++ b/docs/docs/guide/design/materialParser.md
@@ -0,0 +1,80 @@
+---
+title: 入料模块设计
+sidebar_position: 2
+---
+## 介绍
+入料模块负责物料接入,通过自动扫描、解析源码组件,产出一份符合《中后台低代码组件描述协议》的** **JSON Schema。这份 Schema 包含基础信息和属性描述信息部分,低代码引擎会基于它们在运行时自动生成一份 configure 配置,用作设置面板展示。
+
+## npm 包与仓库信息
+
+- npm 包:@alilc/lowcode-material-parser
+- 仓库:[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的 modules/material-parser
+
+## 原理
+入料模块使用动静态分析结合的方案,动态胜在真实,静态胜在细致,不过全都依赖源码中定义的属性,若未定义,或者定义错误,则无法正确入料。
+
+### 整体流程
+大体分为本地化、扫描、解析、转换、校验 5 部分,如下图所示。
+
+
+### 静态解析
+在静态分析时,分为 JS 和 TS 两种情况。
+
+#### 静态解析 JS
+在 JS 情况下,基于 react-docgen 进行扩展,自定义了 resolver 及 handler,前者用于寻找组件定义,后者用于解析 propTypes、defaultProps 等信息,整体流程图如下:
+
+
+
+react-docgen 使用 babel 生成语法树,再使用 ast-types 进行遍历去寻找组件节点及其属性类型定义。原本的 react-docgen 只能解析单文件,且不能解析 IIFE、逗号表达式等语法结构 (一般出现在转码后的代码中)。笔者对其进行改造,使之可以递归解析多文件去查找组件定义,且能够解开 IIFE,以及对逗号表达式进行转换,以方便后续的组件解析。另外,还增加了子组件解析的功能,即类似 `Button.Group = Group` 这种定义。
+
+#### 静态解析 TS
+在 TS 情况下,还要再细分为 TS 源码和 TS 编译后的代码。
+TS 源码中,React 组件具有类型签名;TS 编译后的代码中,dts 文件 (如有) 包含全部的 class / interface / type 类型信息。可以从这些类型信息中获取组件属性描述。整体流程图如下:
+
+
+
+react-docgen 内置了 TypeScript 的 babel 插件,所以也具备解析 interface 的能力,可惜能力有限,babel 只能解析 TS 代码,但没法做类型检查,类型处理是由 react-docgen 实现的,它对于 extends/implements/utility 的情况处理不好,并且没有类型推断,虽然可以对其功能进行完善,不过这种情况下,应该借助 TypeScript Compiler 的能力,而非自己造轮子。通过调研,发现市面上有 typescript-react-docgen 这个项目。它在底层依赖了 TypeScript,且产出的数据格式与 react-docgen 一致,所以我们选择基于它进行解析。
+
+TypeScript Compiler 会递归解析某个文件中出现及引用的全部类型,当然,前提是已经定义或安装了相应的类型声明。typescript-react-docgen 会调用 TypeScript Compiler 的 API,获取每个文件输出的类型,判断其是否为 React 组件。满足下列条件之一的,会被判定为 React 组件:
+
+1. 获取其函数签名,如果只有一个入参,或者第一个入参名称为 props,会被判定为函数式组件;
+2. 获取其 `constructor` 方法,如果其返回值包含 props 属性,会被判定为有状态组件。
+
+然后,遍历组件的 props 类型,获取每个属性的类型签名字符串,比如 `(a: string) => void`。typescript-react-docgen 可以克服 react-docgen 解析 TypeScirpt 类型的问题,但是每个类型都以字符串的形式来呈现,不利于后续的解析。所以,笔者对其进行了扩展,递归解析每一层的属性值。此外,在函数式组件的判定上,笔者做了完善,会看函数的返回值是否为 `ReactElement` ,若是,才为函数式组件。
+
+下面讲对于一些特殊情况的处理。
+
+**循环定义**
+
+TypeScript 类型可以循环定义,比如下面的 JSON 类型:
+
+```typescript
+interface Json {
+ [x: string]: string | number | boolean | Json | JsonArray;
+}
+type JsonArray = Array;
+```
+
+因为低代码组件描述协议中没有引用功能,而且也不方便在界面上展示出来,所以这种循环定义无需完全解析,入料模块会在检测到循环定义的时候,把类型简化为 `object` 。对于特殊的类型,如 JSON,可以用相应的 Setter 来编辑。
+
+**复杂类型**
+TypeScript Compiler 会将合成类型的所有属性展开,比如 `boolean | string`,会被展开为 `true | false | string`,这带来了不必要的精确,我们需要的只是 `boolean | string` 而已。当然,对于这个例子,我们很容易把它还原回 `boolean | string`,然而,对于诸如 `React.ButtonHTMLAttributes & {'data-name': string}` 这种类型,它会把 `ButtonHTMLAttributes` 中众多的属性和 `data-name` 混杂在一起,完全无法分辨,只能以展开的形式提供。这 100 多个属性,如果都放在设置面板,绝对是使用者的噩梦,所以,其结果会被简化为 `object` 。当然,即使没有 `{'data-name': string}`,`ButtonHTMLAttributes` 也是没有单独的 Setter 的,同样会被简化为 `object` 。
+
+### 动态解析
+
+当一个组件,使用静态解析无法入料时,会使用动态解析。
+
+整体流程图如下:
+
+
+
+基本思想很简单,require 组件进来,然后读取其组件类上定义的 propTypes 和 defaultProps 属性。这里使用了 parse-prop-types 库,使用它的时候必须在组件之前引用,因为它会先对 prop-types 库进行修改,在每个 PropTypes 透出的函数上挂上类型,比如 string, number 等等,然后再去遍历。动态解析可以解析出全部的类型信息,因为 PropTypes 有可能引入依赖组件的一些类型定义,这在静态解析中很难做到,或者成本较高,而对于动态解析来说,都由运行时完成了。
+
+##### 技术细节
+
+值得注意的是,有些 js 文件里还会引入 css 文件,而且从笔者了解的情况来看,这种情况在集团内部不在少数。这种组件不配合 webpack 使用,肯定会报错,但是使用 webpack 会明显拖慢速度,所以笔者采用了 sandbox 的方式,对 require 进来的类 css 文件进行 mock。这里,笔者使用了 vm2 这个库,它对 node 自带的 vm 进行了封装,可以劫持文件中的 require 方法。因为 parse-prop-types 的修改在沙箱中会失效,所以笔者也 mock 了组件中的 prop-types 库。
+
+### 整体大图
+把上述的静态解析和动态解析流程结合起来,可以得到以下大图。
+
+
diff --git a/docs/docs/guide/design/renderer.md b/docs/docs/guide/design/renderer.md
new file mode 100644
index 0000000000..4a8c43f329
--- /dev/null
+++ b/docs/docs/guide/design/renderer.md
@@ -0,0 +1,215 @@
+---
+title: 渲染模块设计
+sidebar_position: 4
+---
+## 低代码渲染介绍
+
+
+
+基于 Schema 和物料组件,如何渲染出我们的页面?这一节描述的就是这个。
+
+## npm 包与仓库信息
+
+- React 框架渲染 npm 包:@alilc/lowcode-react-renderer
+- 仓库:[https://github.com/alibaba/lowcode-engine](https://github.com/alibaba/lowcode-engine) 下的
+ - packages/renderer-core
+ - packages/react-renderer
+ - packages/react-simulator-renderer
+
+## 渲染框架原理
+### 整体架构
+
+
+
+- 协议层:基于[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec) 产出的 Schema 作为我们的规范协议。
+- 能力层:提供组件、区块、页面等渲染所需的核心能力,包括 Props 解析、样式注入、条件渲染等。
+- 适配层:由于我们使用的运行时框架不是统一的,所以统一使用适配层将不同运行框架的差异部分,通过接口对外,让渲染层注册/适配对应所需的方法。能保障渲染层和能力层直接通过适配层连接起来,能起到独立可扩展的作用。
+- 渲染层:提供核心的渲染方法,由于不同运行时框架提供的渲染方法是不同的,所以其通过适配层进行注入,只需要提供适配层所需的接口,即可实现渲染。
+- 应用层:根据渲染层所提供的方法,可以应用到项目中,根据使用的方法和规模即可实现应用、页面、区块的渲染。
+
+### 核心解析
+
+这里主要解析一下刚刚提到的架构中的适配层和渲染层。
+
+#### 适配层
+适配层提供的是各个框架之间的差异项。比如 `React.createElement` 和 `Rax.createElement` 方法是不同的。所以需要在适配层对 API 进行抹平。
+
+##### React
+```typescript
+import { createElement } from 'react';
+import {
+ adapter,
+} from '@ali/lowcode-renderer-core';
+
+adapter.setRuntime({
+ createElement,
+});
+```
+##### Rax
+```typescript
+import { createElement } from 'rax';
+import {
+ adapter,
+} from '@ali/lowcode-renderer-core';
+
+adapter.setRuntime({
+ createElement,
+});
+```
+这时,在核心层使用的 `createElement` 会基于使用不同的 renderer 而使用不同的方法,自动适配框架所需的运行时方法。
+
+所需的方法包括:
+
+- `setRuntime`:设置运行时相关方法
+ - `Component`:组件类,参考 React 的 `Component`。
+ - `PureComponent`:组件类,参考 React 的 `PureComponent`。
+ - `createContext`:创建一个 `Context` 对象的方法。例如,当 React 渲染一个订阅了这个 `Context` 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 `Provider` 中读取到当前的 `context` 值。
+ - `createElement`:创建 `Component` 元素,例如在 React 中即为创建 React 元素。
+ - `forwardRef`:ref 转发的方法。Ref 转发是一个可选特性,其允许某些组件接收 ref,并将其向下传递(换句话说,“转发”它)给子组件。
+ - `findDOMNode`:是一个访问底层 DOM 节点的方法。如果组件已经被挂载到 DOM 上,此方法会返回浏览器中相应的原生 DOM 元素。
+- `setRenderers`
+ - `PageRenderer`:页面渲染的方法。可以定制页面渲染的生命周期,定制导航,定制路由等。
+ - `ComponentRenderer`:组件渲染的方法。
+ - `BlockRenderer`:区块渲染的方法。
+
+#### 渲染层
+##### React Renderer
+内部的技术栈统一都是 React,大多数适配层的 API 都是按照 React 来设计的,所以对于 React Renderer 来说,需要做的不多。
+
+React Renderer 的代码量很少,主要是将 React API 注册到适配层中。
+
+```typescript
+import React, { Component, PureComponent, createElement, createContext, forwardRef, ReactInstance, ContextType } from 'react';
+import ReactDOM from 'react-dom';
+import {
+ adapter,
+ pageRendererFactory,
+ componentRendererFactory,
+ blockRendererFactory,
+ addonRendererFactory,
+ tempRendererFactory,
+ rendererFactory,
+ types,
+} from '@ali/lowcode-renderer-core';
+import ConfigProvider from '@alifd/next/lib/config-provider';
+
+window.React = React;
+(window as any).ReactDom = ReactDOM;
+
+adapter.setRuntime({
+ Component,
+ PureComponent,
+ createContext,
+ createElement,
+ forwardRef,
+ findDOMNode: ReactDOM.findDOMNode,
+});
+
+adapter.setRenderers({
+ PageRenderer: pageRendererFactory(),
+ ComponentRenderer: componentRendererFactory(),
+ BlockRenderer: blockRendererFactory(),
+ AddonRenderer: addonRendererFactory(),
+ TempRenderer: tempRendererFactory(),
+ DivRenderer: blockRendererFactory(),
+});
+
+adapter.setConfigProvider(ConfigProvider);
+```
+
+##### Rax Renderer
+Rax 的大多数 API 和 React 基本也是一致的,差异点在于重写了一些方法。
+```typescript
+import { Component, PureComponent, createElement, createContext, forwardRef } from 'rax';
+import findDOMNode from 'rax-find-dom-node';
+import {
+ adapter,
+ addonRendererFactory,
+ tempRendererFactory,
+ rendererFactory,
+} from '@ali/lowcode-renderer-core';
+import pageRendererFactory from './renderer/page';
+import componentRendererFactory from './renderer/component';
+import blockRendererFactory from './renderer/block';
+import CompFactory from './hoc/compFactory';
+
+adapter.setRuntime({
+ Component,
+ PureComponent,
+ createContext,
+ createElement,
+ forwardRef,
+ findDOMNode,
+});
+
+adapter.setRenderers({
+ PageRenderer: pageRendererFactory(),
+ ComponentRenderer: componentRendererFactory(),
+ BlockRenderer: blockRendererFactory(),
+ AddonRenderer: addonRendererFactory(),
+ TempRenderer: tempRendererFactory(),
+});
+```
+
+### 多模式渲染
+#### 预览模式渲染
+预览模式的渲染,主要是通过 Schema、components 即可完成上述的页面渲染能力。
+```typescript
+import ReactRenderer from '@ali/lowcode-react-renderer';
+import ReactDOM from 'react-dom';
+import { Button } from '@alifd/next';
+
+const schema = {
+ componentName: 'Page',
+ props: {},
+ children: [
+ {
+ componentName: 'Button',
+ props: {
+ type: 'primary',
+ style: {
+ color: '#2077ff'
+ },
+ },
+ children: '确定',
+ },
+ ],
+};
+
+const components = {
+ Button,
+};
+
+ReactDOM.render((
+
+), document.getElementById('root'));
+```
+
+#### 设计模式渲染(Simulator)
+设计模式渲染就是将编排生成的《搭建协议》渲染成视图的过程,视图是可以交互的,所以必须要处理好内部数据流、生命周期、事件绑定、国际化等等。也称为画布的渲染,画布是 UI 编排的核心,它一般融合了页面的渲染以及组件/区块的拖拽、选择、快捷配置。
+画布的渲染和预览模式的渲染的区别在于,画布的渲染和设计器之间是有交互的。所以在这里我们新增了一层 `Simulator` 作为设计器和渲染的连接器。
+`Simulator` 是将设计器传入的 `DocumentModel` 和组件/库描述转成相应的 Schema 和 组件类。再调用 Render 层完成渲染。我们这里介绍一下它提供的能力。
+##### 整体架构
+
+
+- `Project`:位于顶层的 Project,保留了对所有文档模型的引用,用于管理应用级 Schema 的导入与导出。
+- `Document`:文档模型包括 Simulator 与数据模型两部分。Simulator 通过一份 Simulator Host 协议与数据模型层通信,达到画布上的 UI 操作驱动数据模型变化。通过多文档的设计及多 Tab 交互方式,能够实现同时设计多个页面,以及在一个浏览器标签里进行搭建与配置应用属性。
+- `Simulator`:模拟器主要承载特定运行时环境的页面渲染及与模型层的通信。
+- `Node`:节点模型是对可视化组件/区块的抽象,保留了组件属性集合 Props 的引用,封装了一系列针对组件的 API,比如修改、编辑、保存、拖拽、复制等。
+- `Props`:描述了当前组件所维系的所有可以「设计」的属性,提供一系列操作、遍历和修改属性的方法。同时保持对单个属性 Prop 的引用。
+- `Prop`:属性模型 Prop 与当前可视化组件/区块的某一具体属性想映射,提供了一系列操作属性变更的 API。
+- `Settings`:`SettingField` 的集合。
+- `SettingField`:它连接属性设置器 `Setter` 与属性模型 `Prop`,它是实现多节点属性批处理的关键。
+- 通用交互模型:内置了拖拽、活跃追踪、悬停探测、剪贴板、滚动、快捷键绑定。
+
+##### 模拟器介绍
+
+
+- 运行时环境:从运行时环境来看,目前我们有 React 生态、Rax 生态。而在对外的历程中,我们也会拥有 Vue 生态、Angular 生态等。
+- 布局模式:不同于 C 端营销页的搭建,中后台场景大多是表单、表格,流式布局是主流的选择。对于设计师、产品来说,是需要绝对布局的方式来进行页面研发的。
+- 研发场景:从研发场景来看,低代码搭建不仅有页面编排,还有诸如逻辑编排、业务编排的场景。
+
+基于以上思考,我们通过基于沙箱隔离的模拟器技术来实现了多运行时环境(如 React、Rax、小程序、Vue)、多模式(如流式布局、自由布局)、多场景(如页面编排、关系图编排)的 UI 编排。通过注册不同的运行时环境的渲染模块,能够实现编辑器从 React 页面搭建到 Rax 页面搭建的迁移。通过注册不同的模拟器画布,你可以基于 G6 或者 mxgraph 来做关系图编排。你可以定制一个流式布局的画布,也可以定制一个自由布局的画布。
diff --git a/docs/docs/guide/design/setter.md b/docs/docs/guide/design/setter.md
new file mode 100644
index 0000000000..7afbbf034f
--- /dev/null
+++ b/docs/docs/guide/design/setter.md
@@ -0,0 +1,92 @@
+---
+title: 设置器设计
+sidebar_position: 6
+---
+
+设置器,又称为 Setter,是作为物料属性和用户交互的重要途径,在编辑器日常使用中有着非常重要的作用,本文重点介绍 Setter 的设计原理和使用方式,帮助用户更好的理解 Setter。
+
+在编辑器的右边区域,Setter 的区块就展现在这里,如下图:
+
+
+
+其中包含 属性、样式、事件、高级:
+
+- 属性:展示该物料常规的属性;
+- 样式:展示该物料样式的属性;
+- 事件:如果该物料有声明事件,则会出现事件面板,用于绑定事件;
+- 高级:两个逻辑相关的属性,**条件渲染**和**循环。**
+## npm 包与仓库信息
+
+- npm 包:@alilc/lowcode-engine-ext
+- 仓库:[https://github.com/alibaba/lowcode-engine-ext](https://github.com/alibaba/lowcode-engine-ext)
+
+## 设置器模块原理
+
+
+
+设置面板依赖于以下三块抽象
+
+- 编辑器上下文 `editor`,主要包含:消息通知、插件引用等
+- 设置对象 `settingTarget`,主要包含:选中的节点、是否同一值、值的储存等
+- 设置列 `settingField`,主要和当前设置视图相关,包含视图的 `ref`、以及设置对象 `settingTarget`
+
+### SettingTarget 抽象
+
+如果不是多选,可以直接暴露 `Node` 给到这,但涉及多选编辑的时候,大家的值通常是不一样的,设置的时候需要批量设置进去,这里主要封装这些逻辑,把多选编辑的复杂性屏蔽掉。
+
+所选节点所构成的**设置对象**抽象如下:
+
+```typescript
+interface SettingTarget {
+ // 所设置的节点集,至少一个
+ readonly nodes: Node[];
+ // 所有属性值数据
+ readonly props: object;
+ // 设置属性值
+ setPropValue(propName: string, value: any): void;
+ // 获取属性值
+ getPropValue(propName: string): any;
+ // 设置多个属性值,替换原有值
+ setProps(data: object): void;
+ // 设置多个属性值,和原有值合并
+ mergeProps(data: object): void;
+ // 绑定属性值发生变化时
+ onPropsChange(fn: () => void): () => void;
+}
+```
+
+基于设置对象所派生的**设置目标属性**抽象如下:
+
+```typescript
+interface SettingTargetProp extends SettingTarget {
+ // 当前属性名称
+ readonly propName: string;
+ // 当前属性值
+ value: any;
+ // 是否设置对象的值一致
+ isSameValue(): boolean;
+ // 是否是空值
+ isEmpty(): boolean;
+ // 设置属性值
+ setValue(value: any): void;
+ // 移除当前设置
+ remove(): void;
+}
+```
+
+### SettingField 抽象
+
+
+```typescript
+interface SettingField extends SettingTarget {
+ // 当前 Field 设置的目标属性,为 group 时此值为空
+ readonly prop?: SettingTargetProp;
+
+ // 当前设置项的 ref 引用
+ readonly ref?: ReactInstance;
+
+ // 属性配置描述传入的配置
+ readonly config: SettingConfig;
+ // others....
+}
+```
diff --git a/docs/docs/guide/design/specs.md b/docs/docs/guide/design/specs.md
new file mode 100644
index 0000000000..2e8e4c195c
--- /dev/null
+++ b/docs/docs/guide/design/specs.md
@@ -0,0 +1,89 @@
+---
+title: 协议栈简介
+sidebar_position: 1
+---
+## 什么是低代码协议
+低代码引擎体系基于三份协议来构建,分别是 [《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)、[《低代码引擎物料协议规范》](/site/docs/specs/material-spec)和[《低代码引擎资产包协议规范》](/site/docs/specs/assets-spec), 它们保障了低代码领域的标准化,成为了生态建设和流通的基石。
+
+
+
+## 为什么需要协议
+
+首先,我们做一个不恰当的类比,我们将低代码引擎和 JavaScript 语言做一下类别。还记得之前,大家都被浏览器兼容性支配的恐惧,特别是 IE 和其他浏览器,对上层 API 实现的不一致,导致一份代码需要运行在两端需要做适配。当浏览器 / JavaScript 相关的标准出现之后,各个浏览器进行了 API 的统一,使得我们终于可以从这部分工作中解放出来(PS:Babel 对于语言特性的转换是另一个方面的问题)。
+
+而在《低代码引擎搭建协议规范》出现之前,低代码领域也有类似的问题。
+
+### 概念不通
+
+在交流的过程中,一些对于搭建产品的术语的不一致,导致了一些沟通成本,不管是在文章分享、技术分享、交流会上,都会有这个问题。
+
+### 物料孤岛
+
+由于低代码产品实现的方式不同,物料的消费方式也各不相同。这里分为两种物料,低代码物料和 ProCode 物料。
+
+对于低代码物料来说,A 平台创建的物料无法使用到 B 平台上,如果想在 B 平台实现同样的物料,需要按照 B 平台的标准搭建一份物料。
+
+对于 ProCode 物料来说,需要在低代码平台进行消费,是需要进行转换的,包括搭建配置项的生成、物料搭建视图等,可能还需要特殊的描述文件进行描述。由于这一层没有统一,同一份 ProCode 物料每接入一个低代码,可能需要的描述文件格式不同,转换的代码不同,使用的工具也不同。
+
+### 生态隔离
+
+不同低代码平台的生态体系也不相同,有的低代码平台的物料生态不错,有的低代码平台的搭建体验生态不错。但是这些利好的生态,都是无法互通的,甚至就算知道了代码也无法复用,因为底层是不一致的。对于阿里巴巴集团来说,每一个平台都创建一份自己的生态,这并不是利好的。
+
+### 低水平重复建设
+
+大家可能觉得,以上问题对于自己造轮子来说,其实也是有利的,因为自己得到了技术上的成长。
+
+但是对于低代码的平台方,实际上更多的工作,在物料的转化、物料的生成、搭建体验的小优化、部分其他平台生态的实现。这些的技术深度其实并不高,属于低水平重复建设部分。
+
+### 价值不高
+
+如果每个业务都要从 0 开始做,做自己的平台,会花费大量的时间来构建底层基础设施,对业务本身而言并不是一件好事;而且前端领域的底层基础设施都大同小异,不同团队重复构建造成了极大的资源浪费。
+
+这样的建设,会导致从 0 到 1 都需要花费大量的时间,往往在内部人力不足、投入有限时,产品很容易在未发展壮大的时候就面临了死亡相关的决策。
+
+设想一下,如果可以开发一份全集团低代码平台都可以使用的物料,是否更有成就感呢?如果可以基于已有生态进行低代码平台的快速落地,而不是花费 1-2 年搭建一个可用的低代码平台,再验证市场。在快速的验证之后,再进行更深入的打磨,这其中的思考和技术含量是否更优于之前的模式呢?
+
+以 2019 年的阿里巴巴的情况举例,不同平台的低代码物料但不限于:
+
+1. vc-deep — vc 协议 + Deep 组件库 (阿里巴巴企业智能团队基于 Fusion Next 定制);
+2. Iceluna 协议 + Fusion Next;
+3. AIMake 物料;
+4. vc-fusion-basic + 业务改造 — vc 协议 + Fusion Next(各业务 Fork 定制);
+5. vision 魔改 + vc 协议扩展 + fusion 业务组件;
+6. vc 协议 + antd;
+
+可以看到,各个搭建平台都需要维护一套自己的基础组件库,这是非常不合理的,对基础组件库的维护会分散开发同学完成业务目标的精力。
+
+建立统一的低代码领域标准化,是百利而无一害的。于是,在阿里巴巴集团 2020 年进行了讨论,建立了搭建治理&物料流通战役,此战役便产出了上文中的协议规范,成为了低代码引擎和其生态的基础。
+
+## 协议的作用
+
+基于统一的协议,我们完成业务组件、区块、模板等各类物料的标准统一,各类中后台研发系统生产的物料可借助物料中心进行跨系统流通,通过丰富物料生态的共享提升各平台研发系统的效率。同时完成低代码引擎的标准统一以及低代码搭建中台能力的输出,帮助业务方快速孵化本业务域中后台研发系统。
+
+### 打破物料孤岛
+
+#### 物料中心
+
+这里以阿里集团的前端物料中间建设为例,在《低代码引擎物料协议规范》落地之后,建立了阿里巴巴各个中后台研发平台沟通、对话的基础,物料流通的先决条件已经成熟,这个时候我们还需要一个统一的物料源,用于管理物料的上传、存储、检索、分发,一个典型的中心化架构,类似 npm 的管理,这便是我们物料中心。
+
+Fusion Market 是物料中心的前身,它提供了业务组件的存储、文档展示和全局透出的功能,由于 fusion 体系在集团内的广泛使用,Fusion Market 沉淀了不少的业务组件,但是这个项目却一直不温不火,只看到业务组件数量的增加,却未看到物料流通起来。其中一个原因是,没有阿里巴巴前端委员会的背书,规范很难统一,规范如果不统一,物料就很难流通;
+
+在规范成立之后,物料中心也将有了建设的基础,最终于 2019 年建立了物料中心,提供了物料流通的平台能力。
+
+#### 低代码基础物料
+
+就像 AntD、Element 之于源码研发模式,在低代码研发模式下各个搭建平台也需要一套统一的、开箱即用的低代码基础组件库。基于低代码描述协议完成了两份低代码基础物料的建设,即“Fusion 低代码基础组件库”和“AntD 低代码基础组件库”。
+
+#### 源码组件低代码化
+
+将源码组件一键转化为低代码物料,符合低代码物料规范,可以在低代码平台进行流通。
+### 低代码物料中心
+
+当低代码物料积累到一定的量级之后,所有的搭建平台的业务物料越来越多。这些物料通过低代码物料中心进行统一的管理和消费。
+### 设置器生态的基础
+
+Snippet(组件默认搭建 schema ) 由《低代码引擎搭建协议规范》定义,低代码引擎会按照规范对组件进行渲染,Configure 由《低代码引擎物料协议规范》定义,它描述了组件的 props 以及每个 prop 对应的设置器 (Prop 配置面板),低代码引擎提供了 20+ 个内置设置器,但如果我们组件的 props 超出了引擎内置设置器的范围,就需要我们自己来开发对应设置器。
+设置器最终也慢慢形成了自己的生态,这使得开发物料更加容易,可以使用已有的生态中的设置器,进行物料配置描述。
+### 低代码引擎实现标准
+
+低代码引擎是以上生态的消费端,它是实现了标准协议的低代码引擎。这是不可或缺的部分,低代码引擎这里就相当于一个标准浏览器,一方面给其他的低代码平台提供了一个 Demo,其他平台可以参考低代码引擎进行实现,满足官方协议,便也可以消费相关的物料生态和其他生态。
diff --git a/docs/docs/guide/design/summary.md b/docs/docs/guide/design/summary.md
new file mode 100644
index 0000000000..38d523cac9
--- /dev/null
+++ b/docs/docs/guide/design/summary.md
@@ -0,0 +1,69 @@
+---
+title: 架构综述
+sidebar_position: 0
+---
+## 分层架构描述
+
+
+我们设计了这样一套分层架构,自下而上分别是协议 - 引擎 - 生态 - 平台。
+
+- 底层协议栈定义的是标准,**标准的统一让上层产物的互通成为可能**。
+- 引擎是**对协议的实现**,同时通过能力的输出,向上**支撑生态开放体系**,提供各种生态扩展能力。
+- 生态就好理解了,是基于引擎核心能力上扩展出来的,比如物料、设置器、插件等,还有工具链支撑开发体系。
+- 最后,各个平台基于引擎内核以及生态中的产品组合、衔接形成满足其需求的低代码平台。
+
+**每一层都明确自身的定位,各司其职,协议不会去思考引擎如何实现,引擎也不会实现具体上层平台功能,上层平台的定制化均通过插件来实现,这些理念将会贯穿我们体系设计、实现的过程。**
+
+## 引擎内核简述
+
+
+
+低代码引擎分为 4 大模块,入料 - 编排 - 渲染 - 出码:
+
+- 入料模块就是将外部的物料,比如海量的 npm 组件,按照[《低代码引擎物料协议规范》](/site/docs/specs/material-spec)进行描述。将描述后的数据通过引擎 API 注册后,在编辑器中使用。
+ > **注意,这里仅是增加描述,而非重写一套,这样我们能最大程度复用 ProCode 体系已沉淀的组件。**
+- 编排,本质上来讲,就是**不断在生成符合[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)的页面描述,将编辑器中的所有物料,进行布局设置、组件 CRUD 操作、以及 JS / CSS 编写/ 逻辑编排 **等,最终转换成页面描述,技术细节后文会展开。
+- 渲染,顾名思义,就是**将编排生成的页面描述结构渲染成视图的过程**,视图是面向用户的,所以必须处理好内部数据流、生命周期、事件绑定、国际化等。
+- 出码,就是**将编排过程产生的符合[《低代码引擎搭建协议规范》](/site/docs/specs/lowcode-spec)的页面描述转换成另一种 DSL 或 编程语言代码的过程**。
+
+## 引擎生态简述
+
+
+
+
+
+引擎生态主要分为 3 部分,物料、设置器和插件。
+
+### 物料生态
+
+物料是低代码平台的生产资料,没有物料低代码平台则变成了无源之水无本之木。低代码平台的物料即低代码组件。因此低代码物料生态指的是:
+1. 低代码物料生产能力和规范。
+2. 对低代码物料进行统一管理的物料中心。
+3. 基于 Fusion Next 的低代码基础组件库。
+
+### 设置器生态
+
+对于已接入物料的属性配置,需要不同的设置器。
+
+比如配置数值类型的 age,需要一个数值设置器,配置对象类型的 hobby,需要一个对象设置器,依次类推。
+
+每个设置器本质上都是一个 React 组件,接受由引擎传入的参数,比如 value 和 onChange,value 是初始传入的值,onChange 是在设置器的值变化时的回传函数,将值写回到引擎中。
+
+```typescript
+// 一个最简单的文本设置器示例
+class TextSetter extends Component {
+ render() {
+ const { value, onChange } = this.props;
+ return onChange(e.target.value)} />;
+ }
+}
+```
+
+大多数组件所使用的设置器都是一致或相似的。如同建设低代码基础组件库一样,设置器生态是一组基础的设置器,供大多数组件配置场景使用。
+
+同时提供了设置器的定制功能。
+
+### 插件生态
+低代码引擎本身只包含了最小的内核,而我们所能看到的设计器上的按钮、面板等都是插件提供的。插件是组成设计器的必要部分。
+
+因此我们提供了一套官方的插件生态,提供最基础的设计器功能。帮助用户通过使用插件,快速完成自己的设计器。
diff --git a/docs/docs/guide/expand/_category_.json b/docs/docs/guide/expand/_category_.json
new file mode 100644
index 0000000000..15aeb3dea1
--- /dev/null
+++ b/docs/docs/guide/expand/_category_.json
@@ -0,0 +1,6 @@
+{
+ "label": "扩展低代码编辑器",
+ "position": 2,
+ "collapsed": false,
+ "collapsible": true
+}
diff --git a/docs/docs/guide/expand/editor/_category_.json b/docs/docs/guide/expand/editor/_category_.json
new file mode 100644
index 0000000000..52662a9d1e
--- /dev/null
+++ b/docs/docs/guide/expand/editor/_category_.json
@@ -0,0 +1,6 @@
+{
+ "label": "扩展编辑态",
+ "position": 1,
+ "collapsed": false,
+ "collapsible": true
+}
diff --git a/docs/docs/guide/expand/editor/cli.md b/docs/docs/guide/expand/editor/cli.md
new file mode 100644
index 0000000000..0577a181db
--- /dev/null
+++ b/docs/docs/guide/expand/editor/cli.md
@@ -0,0 +1,198 @@
+---
+title: 低代码生态脚手架 & 调试机制
+sidebar_position: 10
+---
+## 脚手架简述
+
+在 fork 低代码编辑器 demo 项目后,您可以直接在项目中任意扩展低代码编辑器。如果您想要将自己的组件/插件/设置器封装成一个独立的 npm 包并提供给社区,您可以使用我们的低代码脚手架建立低代码扩展。
+
+> Windows 开发者请在 WSL 环境下使用开发工具
+>
+> WSL 中文 doc:[https://docs.microsoft.com/zh-cn/windows/wsl/install](https://docs.microsoft.com/zh-cn/windows/wsl/install)
+>
+> 中文教程:[https://blog.csdn.net/weixin_45027467/article/details/106862520](https://blog.csdn.net/weixin_45027467/article/details/106862520)
+
+
+## 脚手架功能
+### 脚手架初始化
+
+```bash
+npm init @alilc/element your-element-name
+```
+不写 your-element-name 的情况下,则在当前目录创建。
+
+> 注 1:如遇错误提示 `sh: create-element: command not found` 可先执行下述命令
+```bash
+npm install -g @alilc/create-element
+```
+
+> 注 2:觉得安装速度比较慢的同学,可以设置 npm 国内镜像,如
+```bash
+npm init @alilc/element your-element-name --registry=https://registry.npmmirror.com
+```
+
+选择对应的元素类型,并填写对应的问题,即可完成创建。
+
+
+
+### 脚手架本地环境调试
+
+```bash
+cd your-element-name
+npm install
+npm start
+```
+
+### 脚手架构建
+
+```bash
+npm run build
+```
+
+### 脚手架发布
+
+修改版本号后,执行如下指令即可:
+
+```bash
+npm publish
+```
+
+## 🔥🔥🔥 在低代码项目中调试物料/插件/设置器
+
+> 📢📢📢 低代码生态脚手架提供的调试利器,在启动 setter/插件/物料 项目后,直接在已有的低代码平台就可以调试,不需要 npm link / 手改 npm main 入口等传统方式,轻松上手,强烈推荐使用!!
+
+### 组件/插件/Setter 侧
+
+1. 插件/setter 在原有 alt 的配置中添加相关的调试配置
+ ```json
+ // build.json 中
+ {
+ "plugins": [
+ [
+ "@alilc/build-plugin-alt",
+ {
+ "type": "plugin",
+ "inject": true, // 开启注入调试
+ // 配置要打开的页面,在注入调试模式下,不配置此项的话不会打开浏览器
+ // 支持直接使用官方 demo 项目:https://lowcode-engine.cn/demo/index.html
+ "openUrl": "https://lowcode-engine.cn/demo/index.html?debug"
+ }
+ ],
+ ]
+ }
+ ```
+
+2. 组件需先安装 @alilc/build-plugin-alt,再将组件内的 `build.lowcode.js`文件修改如下
+ ```javascript
+ const { library } = require('./build.json');
+
+ module.exports = {
+ alias: {
+ '@': './src',
+ },
+ plugins: [
+ [
+ // lowcode 的配置保持不变,这里仅为示意。
+ '@alifd/build-plugin-lowcode',
+ {
+ library,
+ engineScope: "@alilc"
+ },
+ ],
+ [
+ '@alilc/build-plugin-alt',
+ {
+ type: 'component',
+ inject: true,
+ library,
+ // 配置要打开的页面,在注入调试模式下,不配置此项的话不会打开浏览器
+ // 支持直接使用官方 demo 项目:https://lowcode-engine.cn/demo/index.html
+ openUrl: "https://lowcode-engine.cn/demo/index.html?debug"
+ }
+ ]],
+ };
+ ```
+
+3. 本地组件/插件/Setter正常启动调试,在项目的访问地址增加 debug,即可开启注入调试。
+ ```url
+ https://lowcode-engine.cn/demo/demo-general/index.html?debug
+ ```
+
+### 项目侧的准备
+
+> 如果你的低代码项目 fork 自官方 demo,那么项目侧的准备已经就绪,不用再看以下内容~
+
+1. 安装 @alilc/lowcode-plugin-inject
+ ```bash
+ npm i @alilc/lowcode-plugin-inject --save-dev
+ ```
+
+2. 在引擎初始化侧引入插件
+ ```typescript
+ import Inject, { injectAssets } from '@alilc/lowcode-plugin-inject';
+ import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+
+ export default async () => {
+ // 注意 Inject 插件必须在其他插件前注册,且所有插件的注册必须 await
+ await plugins.register(Inject);
+ await plugins.register(OtherPlugin);
+ await plugins.register((ctx: IPublicModelPluginContext) => {
+ return {
+ name: "editor-init",
+ async init() {
+ // 设置物料描述前,使用插件提供的 injectAssets 进行处理
+ const { material, project } = ctx;
+ material.setAssets(await injectAssets(assets));
+ },
+ };
+ });
+ }
+ ```
+
+3. 在 saveSchema 时过滤掉插入的 url,避免影响渲染态
+ ```typescript
+ import { filterPackages } from '@alilc/lowcode-plugin-inject';
+ export const saveSchema = async () => {
+ // ...
+ const packages = await filterPackages(editor.get('assets').packages);
+ window.localStorage.setItem(
+ 'packages',
+ JSON.stringify(packages),
+ );
+ // ...
+ };
+ ```
+
+4. 如果希望预览态也可以注入调试组件,则需要在 preview 逻辑里插入组件
+ ```javascript
+ import { injectComponents } from '@alilc/lowcode-plugin-inject';
+
+ async function init() {
+ // 在传递给 ReactRenderer 前,先通过 injectComponents 进行处理
+ const components = await injectComponents(buildComponents(libraryMap, componentsMap));
+ // ...
+ }
+ ```
+
+注:若控制台出现如下错误,直接访问一次该 url 即可~
+
+
+
+
+## Meta 信息
+meta 信息是放在生态元素 package.json 中的一小段 json,用户可以通过 meta 了解到这个元素的一些基本信息,如元素类型,一些入口信息等。
+
+```typescript
+interface LcMeta {
+ type: 'plugin' | 'setter' | 'component'; // 元素类型,尚未实现
+ pluginName: string; // 插件名,仅插件包含
+ meta: {
+ dependencies: string[]; // 插件依赖的其他插件列表,仅插件包含
+ engines: {
+ lowcodeEngine: string; // 适配的引擎版本
+ }
+ prototype: string; // 物料描述入口,仅组件包含,尚未实现
+ prototypeView: string; // 物料设计态入口,仅组件包含,尚未实现
+ }
+}
+```
diff --git a/docs/docs/guide/expand/editor/graph.md b/docs/docs/guide/expand/editor/graph.md
new file mode 100644
index 0000000000..a45f34baf0
--- /dev/null
+++ b/docs/docs/guide/expand/editor/graph.md
@@ -0,0 +1,155 @@
+---
+title: 图编排扩展
+sidebar_position: 8
+---
+## 项目运行
+### 前置准备
+1. 参考 https://lowcode-engine.cn/site/docs/guide/quickStart/start
+2. 参考至Demo下载 https://lowcode-engine.cn/site/docs/guide/quickStart/start#%E4%B8%8B%E8%BD%BD-demo
+### 选择demo-graph-x6
+在根目录下执行:
+```bash
+cd demo-graph-x6
+```
+### 安装依赖
+在 lowcode-demo/demo-graph-x6目录下执行:
+```bash
+npm install
+```
+### 启动Demo
+在 lowcode-demo/demo-graph-x6 目录下执行:
+```bash
+npm run start
+```
+之后就可以通过 http://localhost:5556/ 来访问我们的 DEMO 了。
+
+## 认识Demo
+这里的Demo即通过图编排引擎加入了几个简单的物料而来,已经是可以面向真是用户的产品界面。
+
+### 区域组成
+#### 顶部:操作区
+- 右侧:保存到本地、重置页面、自定义按钮
+#### 顶部:工具区
+- 左侧:删除、撤销、重做、放大、缩小
+#### 左侧:面板与操作区
+- 物料面板:可以查找节点,并在此拖动节点到编辑器画布中
+#### 中部:可视化页面编辑画布区域
+- 点击节点/边在右侧面板中能够显示出对应组件的属性配置选项
+- 拖拽修改节点的排列顺序
+#### 右侧:组件级别配置
+- 选中的组件:从页面开始一直到当前选中的节点/边位置,点击对应的名称可以切换到对应的节点上
+- 选中组件的配置:属性:节点的基础属性值设置
+
+> 每个区域的组成都可以被替换和自定义来生成开发者需要的业务产品。
+
+## 目录介绍
+
+
+- public:与其他demo保持一致,均是lowcode engine所必要依赖
+- src
+ - plugins::自定义插件,完成了x6的切面回调处理功能
+ - services:mock数据,真实场景中可能为异步获取数据
+
+## 开发插件
+```typescript
+function pluginX6DesignerExtension(ctx: IPublicModelPluginContext) {
+ return {
+ init() {
+ // 获取 x6 designer 内置插件的导出 api
+ const x6Designer = ctx.plugins['plugin-x6-designer'] as IDesigner;
+
+ x6Designer.onNodeRender((model, node) => {
+ // @ts-ignore
+ // 自定义 node 渲染逻辑
+ const { name, title } = model.propsData;
+ node.attr('text/textWrap/text', title || name);
+ });
+
+ x6Designer.onEdgeRender((model, edge) => {
+ // @ts-ignore
+ const { source, target, sourcePortId, targetPortId } = model.propsData;
+ console.log(sourcePortId, targetPortId);
+ requestAnimationFrame(() => {
+ edge.setSource({ cell: source, port: sourcePortId });
+ edge.setTarget({ cell: target, port: targetPortId });
+ });
+
+ // https://x6.antv.vision/zh/docs/tutorial/intermediate/edge-labels x6 标签模块
+ // appendLabel 会触发 onEdgeLabelRender
+ edge.appendLabel({
+ markup: Markup.getForeignObjectMarkup(),
+ attrs: {
+ fo: {
+ width: 120,
+ height: 30,
+ x: -60,
+ y: -15,
+ },
+ },
+ });
+ });
+
+ x6Designer.onEdgeLabelRender((args) => {
+ const { selectors } = args
+ const content = selectors.foContent as HTMLDivElement
+ if (content) {
+ ReactDOM.render(自定义 react 标签
, content)
+ }
+ })
+ }
+ }
+}
+
+pluginX6DesignerExtension.pluginName = 'plugin-x6-designer-extension';
+
+export default pluginX6DesignerExtension;
+```
+x6Designer为图实例暴露出来的一些接口,可基于此进行一些图的必要插件的封装,整个插件的封装完全follow低代码引擎的插件,详情可参考 https://lowcode-engine.cn/site/docs/guide/expand/editor/pluginWidget
+
+## 开发物料
+```bash
+npm init @alilc/element your-material-demo
+```
+
+
+仓库初始化完成
+
+
+接下来即可编写物料内容了
+图物料与低代码的dom场景存在画布的差异,因此暂不支持物料单独调试,须通过项目demo进行物料调试
+
+### 资产描述
+```bash
+npm run lowcode:build
+```
+如果物料是个React组件,则在执行上述命令时会自动生成对应的meta.ts,但图物料很多时候并非一个React组件,因此须手动生产meta.ts
+
+可参考: https://github.com/alibaba/lowcode-materials/blob/main/packages/graph-x6-materials/lowcode/send-email/meta.ts
+同时会自动生成物料描述文件
+
+### 物料调试
+#### 物料侧
+物料想要支持被项目动态inject调试,须在build.lowcode.js中加入
+```javascript
+[
+ '@alilc/build-plugin-alt',
+ {
+ type: 'component',
+ inject: true,
+ library
+ },
+]
+```
+
+
+本地启动
+```bash
+npm run lowcode:dev
+```
+#### 项目侧
+通过@alilc/lce-graph-core加载物料的天然支持了debug,因此无须特殊处理。
+若项目中自行加载,则参考 https://lowcode-engine.cn/site/docs/guide/expand/editor/cli
+项目访问地址后拼接query "?debug"即可进入物料调试
+
+
+
diff --git a/docs/docs/guide/expand/editor/material.md b/docs/docs/guide/expand/editor/material.md
new file mode 100644
index 0000000000..6e4979553b
--- /dev/null
+++ b/docs/docs/guide/expand/editor/material.md
@@ -0,0 +1,292 @@
+---
+title: 物料扩展
+sidebar_position: 1
+---
+## 物料简述
+物料是页面搭建的原料,按照粒度可分为组件、区块和模板:
+
+1. 组件:组件是页面搭建最小的可复用单元,其只对外暴露配置项,用户无需感知其内部实现;
+2. 区块:区块是一小段符合低代码协议的 schema,其内部会包含一个或多个组件,用户向设计器中拖入一个区块后可以随意修改其内部内容;
+3. 模板:模板和区块类似,也是一段符合低代码协议的 schema,不过其根节点的 componentName 需固定为 Page,它常常用于初始化一个页面;
+
+低代码编辑器中的物料需要进行一定的配置和处理,才能让用户在低代码平台使用起来。这个过程中,需要一份一份配置文件,也就是资产包。资产包文件中,针对每个物料定义了它们在低代码编辑器中的使用描述。
+## 资产包配置
+### 什么是低代码资产包
+
+在低代码 Demo 中,我们可以看到,组件面板不只提供一个组件,组件是以集合的形式提供给低代码平台的,而低代码资产包正是这些组件构成集合的形式。
+**_它背后的 Interface,_**[**_在引擎中的定义摘抄如下_**](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/assets.ts)**_:_**
+
+```typescript
+export interface Assets {
+ version: string; // 资产包协议版本号
+ packages?: Array; // 大包列表,external 与 package 的概念相似,融合在一起
+ components: Array | Array; // 所有组件的描述协议列表
+ sort: ComponentSort; // 新增字段,用于描述组件面板中的 tab 和 category
+}
+
+export interface ComponentSort {
+ groupList?: String[]; // 用于描述组件面板的 tab 项及其排序,例如:["精选组件", "原子组件"]
+ categoryList?: String[]; // 组件面板中同一个 tab 下的不同区间用 category 区分,category 的排序依照 categoryList 顺序排列;
+}
+
+export interface RemoteComponentDescription {
+ exportName: string; // 组件描述导出名字,可以通过 window[exportName] 获取到组件描述的 Object 内容;
+ url: string; // 组件描述的资源链接;
+ package: { // 组件 (库) 的 npm 信息;
+ npm: string;
+ }
+}
+```
+资产包协议 TS 描述
+### Demo 中的资产包
+在 Demo 项目中,自带了一份默认的资产包:
+> [https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/services/assets.json](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/services/assets.json)
+
+这份资产包里的物料是我们内部沉淀出的,用户可以通过这套资产包体验引擎提供的搭建、配置能力。
+**_在项目中正常注册资产包:_**
+```typescript
+import { material } from '@alilc/lowcode-engine';
+// 以任何方式引入 assets
+material.setAssets(assets);
+```
+**_以支持调试的方式注册资产包:_**
+> 这样启动并部署出来的项目,可以通过在预览地址加上 ?debug 来调试本地物料。
+> 例如:
+> - 通过插件初始化一个物料
+> - 按照参考文章配置物料支持调试
+> - 启动物料
+> - 访问:[https://lowcode-engine.cn/demo/demo-general/index.html?debug](https://lowcode-engine.cn/demo/demo-general/index.html)
+>
+详细参考:[低代码生态脚手架 & 调试机制](https://lowcode-engine.cn/site/docs/guide/expand/editor/cli)
+
+```typescript
+import { material } from '@alilc/lowcode-engine';
+import Inject, { injectAssets } from '@alilc/lowcode-plugin-inject';
+await material.setAssets(await injectAssets(assets));
+```
+
+### 手工配置资产包
+参考 Demo 中的[基础 Fusion Assets 定义](https://github.com/alibaba/lowcode-demo/blob/main/demo-basic-fusion/src/services/assets.json),如果我们修改 assets.json,我们就能做到配置资产包:
+
+- packages 对象:我们需要在其中定义这个包的获取方式,如果不定义,就不会被低代码引擎动态加载并对应上组件实例。定义方式是 UMD 的包,低代码引擎会尝试在 window 上寻找对应 library 的实例;
+- components 对象:我们需要在其中定义物料描述,物料描述我们将在下一节继续讲解。
+## 物料描述配置
+### 什么是物料描述
+在低代码平台中,用户是不同的,有可能是开发、测试、运营、设计,也有可能是销售、行政、HR 等等各种角色。他们大多数不具备专业的前端开发知识,对于低代码平台来说,我们使用组件的流程如下:
+
+1. 用户通过拖拽/选择组件,在画布中看到组件;
+2. 选中组件,出现组件的配置项;
+3. 修改组件配置项;
+4. 画布更新生效。
+
+**_当我们选中一个组件,我们可以看到面板右侧会显示组件的配置项。_**
+
+**_它包含以下内容:_**
+
+1. 基础信息:描述组件的基础信息,通常包含包信息、组件名称、标题、描述等。
+2. 组件属性信息:描述组件属性信息,通常包含参数、说明、类型、默认值 4 项内容。
+3. 能力配置/体验增强:推荐用于优化搭建产品编辑体验,定制编辑能力的配置信息。
+
+因此,我们设计了[**《中后台低代码组件描述协议》**](/site/docs/specs/material-spec)来描述一个低代码编辑器中可被配置的内容。
+### Demo 中的物料描述
+我们可以从 Demo 中的 assets.json 找到如下三个物料描述:
+
+- @alifd/pro-layout:布局组件,放在`window.AlifdProLayoutMeta`,[meta 文件地址](https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/meta.js);
+- @alifd/fusion-ui:精选组件,放在`window.AlifdFusionUiMeta`,[meta 文件地址](https://alifd.alicdn.com/npm/@alifd/fusion-ui@1.0.5-beta.1/build/lowcode/meta.js);
+- @alilc/lowcode-materials:原子组件,放在 `window.AlilcLowcodeMaterialsMeta`,[meta 文件地址](https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.1/build/lowcode/meta.js);
+
+**_引擎中,会尝试调用对应 meta 文件,并注入到全局:_**
+```tsx
+const src = 'https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.5/build/lowcode/meta.js';
+const script = document.createElement('script');
+script.src = src;
+document.head.appendChild(script);
+```
+然后在 window 上就能拿到对应的物料描述内容了:
+
+手工配置物料描述时,可以用这样的方式参考一下 Demo 中的物料描述是如何实现的。
+### 手工配置物料描述
+详见:“物料描述详解”章节。
+## 物料的低代码开发
+> _**注意:引擎提供的 cli 并未对 windows 系统做适配,windows 环境必须使用 **_[_**WSL**_](https://docs.microsoft.com/zh-cn/windows/wsl/install)_**,其他终端不保证能正常运行**_
+
+您可以通过本节内容,完成一个组件在低代码编辑器中的配置和调试。
+### 前言(必读)
+引擎提供的物料开发脚手架内置了**_入料模块_**,初始化的时候会自动根据源码解析出一份_**低代码描述**_,但是从源码解析出来的低代码描述让用户直接使用是不够精细的,因为源码包含的信息不够,它没办法完全包含配置项的交互;
+
+比如设计师出了上面的设计稿,这里面除了有哪些 props 可被配置,通过哪个设置器配置,还包含了 props 之间的聚合、排序,甚至有自定义 setter,这些信息源码里是不具备的,需要在低代码描述里进行开发;
+**_因此我们建议只把 cli 初始化的低代码描述作为启动,要根据用户习惯对配置项进行设计,然后人工地去开发调试直接的低代码描述。_**
+### 新开发组件
+#### 组件项目初始化
+```bash
+npm init @alilc/element your-material-name
+```
+#### 选择组件类型
+> 组件 -> <组件组织方式>
+
+
+这里我们选择 react-组件库,之后便生出我们的组件库项目,目录结构如下:
+```
+my-materials
+├── README.md
+├── components (业务组件目录)
+│ ├── ExampleComponent // 业务组件1
+│ │ ├── build // 【编译生成】【必选】
+│ │ │ └── index.html // 【编译生成】【必选】可直接预览文件
+│ │ ├── lib // 【编译生成】【必选】
+│ │ │ ├── index.js // 【编译生成】【必选】js 入口文件
+│ │ │ ├── index.scss // 【编译生成】【必选】css 入口文件
+│ │ │ └── style.js // 【编译生成】【必选】js 版本 css 入口文件,方便去重
+│ │ ├── demo // 【必选】组件文档,用于生成组件开发预览,以及生成组件文档
+│ │ │ └── basic.md
+│ │ ├── src // 【必选】组件源码
+│ │ │ ├── index.js // 【必选】,组件出口文件
+│ │ │ └── main.scss // 【必选】,仅包含组件自身样式的源码文件
+│ │ ├── README.md // 【必选】,组件说明及API
+│ │ └── package.json // 【必选】
+└── └── ExampleComponent2 // 业务组件2
+```
+#### 组件开发与调试
+```bash
+# 安装依赖
+npm install
+
+# 启动 lowcode 环境进行调试预览
+npm run lowcode:dev
+
+# 构建低代码产物
+npm run lowcode:build
+```
+执行上述命令后会在组件 (库) 根目录生成一个 `lowcode` 文件夹,里面会包含每个组件的低代码描述:
+
+
+在 src/components 目录新增一个组件并在 src/index.tsx 中导出,然后再执行 npm run lowcode:dev 时,低代码插件会在 lowcode/ 目录自动生成新增组件的低代码描述(meta.ts)。
+
+用户可以直接修改低代码描述来修改组件的配置:
+
+- 设置组件的 setter(上一个章节介绍的设置器,也可以定制设置器用到物料中);
+- 新增组件配置项;
+- 更改当前配置项;
+#### 配置示例
+隐藏一个 prop
+```typescript
+{
+ name: 'dataSource',
+ condition: () => false,
+}
+```
+展示样式
+```typescript
+{
+ name: 'dataSource',
+ display: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry', // 常用的是 inline(默认), block、entry
+}
+```
+#### 编辑态视图
+用户可以在 lowcode/ 目录下新增 view.tsx 来增加编辑态视图。编辑态视图用于在编辑态时展示与真实预览不一样的视图。
+view.tsx 输出的也是一个 React 组件。
+
+注意:如果是单组件,而非组件库模式的话,view.tsx 应置于 lowcode 而非 lowcode/ 目录下
+
+
+#### 发布组件
+```bash
+# 在组件根目录下,执行
+$ npm publish
+```
+### 现存组件低代码化
+组件低代码化是指,在引入低代码平台之前,我们大多数都是使用源码开发的组件,也就是 ProCode 组件。
+
+在引入低代码平台之后,原来的源码组件是需要转化为低代码物料,这样才能在低代码平台进行消费。
+
+所以接下来会说明,对于已有的源码组件,我们如何把它低代码化。
+#### 配置低代码开发环境
+在您的组件开发环境中,安装 [build-scripts](https://github.com/ice-lab/build-scripts) 和它的低代码开发插件:
+```bash
+npm install -D @alifd/build-plugin-lowcode @alib/build-scripts --save-dev
+```
+新增 build-scripts 配置文件:build.lowcode.js
+
+```javascript
+module.exports = {
+ alias: {
+ '@': './src',
+ },
+ plugins: [
+ [
+ "@alifd/build-plugin-lowcode",
+ {
+ engineScope: '@alilc',
+ }
+ ]
+ ],
+};
+
+```
+在 package.json 中定义低代码开发相关命令
+```javascript
+"lowcode:dev": "build-scripts start --config ./build.lowcode.js",
+"lowcode:build": "build-scripts build --config ./build.lowcode.js",
+```
+
+#### 开发调试
+
+```bash
+# 启动低代码开发调试环境
+npm run lowcode:dev
+```
+
+组件开发形式还和原来的保持一致,但是新增了一份组件的配置文件,其中配置方式和低代码物料的配置是一样的。
+
+#### 构建
+
+```bash
+# 构建低代码产物
+npm run lowcode:build
+```
+
+#### 发布组件
+```bash
+# 在组件根目录下,执行
+npm publish
+```
+
+## 在项目中引入组件 (库)
+> 以下内容可观看[《阿里巴巴低代码引擎项目实战 (3)-自定义组件接入》](https://www.bilibili.com/video/BV1dZ4y1m76S/)直播回放
+
+对于平台或者用户来说,可能所需要的组件集合是不同的。如果需要自定义组件集合,就需要定制资产包,定制的资产包是配置了一系列组件的,将这份资产包用于引擎即可在引擎中使用自定义的组件集合。
+
+### 管理一份资产包
+项目中使用的组件相关资源都需要在资产包中定义,那么我们自己开发的组件库如果要在项目中使用,只需要把组件构建好的相关资源 merge 到 assets.json 中就可以;
+
+#### 自定义组件加入到资产包
+通过官方脚手架自定义组件构建发布之后,npm 包里会出现一个 `build/lowcode/assets-prod.json`文件,我们只需要把该文件的内容 merge 到项目的 assets.json 中就可以;
+
+#### 资产包托管
+
+- 最简单的方式就是类似[引擎 demo 项目](https://github.com/alibaba/lowcode-demo/blob/main/demo-general/src/services/assets.json)的做法,在项目中维护一份 assets.json,新增组件或者组件版本更新都需要修改这份资产包;
+- 灵活一点的做法是通过 oss 等服务维护一份远程可配置的 assets.json,新增组件或者组件更新只需要修改这份远程的资产包,项目无需更新;
+- 再高级一点的做法是实现一个资产包管理的服务,能够通过用户界面去更新资产包的内容;
+
+### 在项目中引入资产包
+```typescript
+import { material, plugins } from '@alilc/lowcode-engine';
+import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+
+// 动态加载 assets
+plugins.register((ctx: IPublicModelPluginContext) => {
+ return {
+ name: 'ext-assets',
+ async init() {
+ try {
+ // 将下述链接替换为您的物料即可。无论是通过 utils 从物料中心引入,还是通过其他途径如直接引入物料描述
+ const res = await window.fetch('https://fusion.alicdn.com/assets/default@0.1.95/assets.json');
+ const assets = await res.text();
+ material.setAssets(assets);
+ } catch (err) {
+ console.error(err);
+ }
+ },
+ }
+}).catch(err => console.error(err));
+```
diff --git a/docs/docs/guide/expand/editor/metaSpec.md b/docs/docs/guide/expand/editor/metaSpec.md
new file mode 100644
index 0000000000..dda16a9cb3
--- /dev/null
+++ b/docs/docs/guide/expand/editor/metaSpec.md
@@ -0,0 +1,565 @@
+---
+title: 物料描述详解
+sidebar_position: 2
+---
+## 物料描述概述
+
+中后台前端体系中,存在大量的组件,程序员可以通过阅读文档,知悉组件的用法。可是搭建平台无法理解 README,而且很多时候,README 里并没有属性列表。这时,我们需要一份额外的描述,来告诉低代码搭建平台,组件接受哪些属性,又是该用怎样的方式来配置这些属性,于是,[**《中后台低代码组件描述协议》**](/site/docs/specs/material-spec)应运而生。协议主要包含三部分:基础信息、属性信息 props、能力配置/体验增强 configure。
+
+物料配置,就是产出一份符合[**《中后台低代码组件描述协议》**](/site/docs/specs/material-spec)的 JSON Schema。如果需要补充属性描述信息,或需要定制体验增强部分(如修改 Setter、调整展示顺序等),就可以通过修改这份 Schema 来实现。目前有自动生成、手工配置这两种方式生成物料描述配置。
+
+## 可视化生成物料描述
+
+使用 Parts 造物平台:[使用文档](/site/docs/guide/expand/editor/parts/partsIntro)
+
+## 自动生成物料描述
+
+可以使用官方提供的 `@alilc/lowcode-material-parser` 解析本地组件,自动生成物料描述。把物料描述放到资产包定义中,就能让低代码引擎理解如何制作物料。详见上一个章节“物料扩展”。
+
+下面以某个组件代码片段为例:
+```typescript
+// /path/to/component
+import { PureComponent } from 'react';
+import PropTypes from 'prop-types';
+
+export default class FusionForm extends PureComponent {
+ static displayName = 'FusionForm';
+
+ static defaultProps = {
+ name: '张三',
+ age: 18,
+ friends: ['李四','王五','赵六'],
+ }
+
+ static propTypes = {
+ /**
+ * 这是用于描述姓名
+ */
+ name: PropTypes.string.isRequired,
+ /**
+ * 这是用于描述年龄
+ */
+ age: PropTypes.number,
+ /**
+ * 这是用于描述好友列表
+ */
+ friends: PropTypes.array
+ };
+
+ render() {
+ return dumb
;
+ }
+}
+```
+
+引入 parse 工具自动解析
+
+```typescript
+import parse from '@alilc/lowcode-material-parser';
+(async () => {
+ const result = await parse({ entry: '/path/to/component' });
+ console.log(JSON.stringify(result, null, 2));
+})();
+```
+
+因为一个组件可能输出多个子组件,所以解析结果是个数组。
+
+```json
+[
+ {
+ "componentName": "FusionForm",
+ "title": "",
+ "docUrl": "",
+ "screenshot": "",
+ "devMode": "proCode",
+ "npm": {
+ "package": "",
+ "version": "",
+ "exportName": "default",
+ "main": "",
+ "destructuring": false,
+ "subName": ""
+ },
+ "props": [
+ {
+ "name": "name",
+ "propType": "string",
+ "description": "这是用于描述姓名",
+ "defaultValue": "张三"
+ },
+ {
+ "name": "age",
+ "propType": "number",
+ "description": "这是用于描述年龄",
+ "defaultValue": 18
+ },
+ {
+ "name": "friends",
+ "propType": "array",
+ "description": "这是用于描述好友列表",
+ "defaultValue": [
+ "李四",
+ "王五",
+ "赵六"
+ ]
+ }
+ ]
+ }
+]
+```
+
+## 手工配置物料描述
+
+如果自动生成的物料无法满足需求,我们就需要手动配置物料描述。本节将分场景描述物料配置的内容。
+
+### 常见配置
+
+#### 组件的属性只有有限的值
+
+增加一个 size 属性,只能从 'large'、'normal'、'small' 这个候选值中选择。
+
+以上面自动解析的物料为例,在此基础上手工加上 size 属性:
+
+```json
+[
+ {
+ "componentName": "FusionForm",
+ "title": "",
+ "docUrl": "",
+ "screenshot": "",
+ "devMode": "proCode",
+ "npm": {
+ "package": "",
+ "version": "",
+ "exportName": "default",
+ "main": "",
+ "destructuring": false,
+ "subName": ""
+ },
+ "props": [
+ {
+ "name": "name",
+ "propType": "string",
+ "description": "这是用于描述姓名",
+ "defaultValue": "张三"
+ },
+ {
+ "name": "age",
+ "propType": "number",
+ "description": "这是用于描述年龄",
+ "defaultValue": 18
+ },
+ {
+ "name": "friends",
+ "propType": "array",
+ "description": "这是用于描述好友列表",
+ "defaultValue": [
+ "李四",
+ "王五",
+ "赵六"
+ ]
+ }
+ ],
+ // 手工增加的 size 属性
+ "configure": {
+ "isExtend": true,
+ "props": [
+ {
+ "title": "尺寸",
+ "name": "size",
+ "setter": {
+ "componentName": 'RadioGroupSetter',
+ "isRequired": true,
+ "props": {
+ "options": [
+ { "title": "大", "value": "large" },
+ { "title": "中", "value": "normal" },
+ { "title": "小", "value": "small" }
+ ]
+ },
+ }
+ }
+ ]
+ }
+ }
+]
+```
+
+#### 组件的属性既可以设置固定值,也可以绑定到变量
+
+我们知道一种属性形式就需要一种 setter 来设置,如果想要将 value 属性允许输入字符串,那就需要设置为 `StringSetter`,如果允许绑定变量,就需要设置为 `VariableSetter`,具体设置器请参考[预置设置器列表](/site/docs/guide/appendix/setters)。
+
+那如果都想要呢?可以使用 `MixedSetter` 来实现。
+
+```javascript
+{
+ // ...
+ configure: {
+ isExtend: true,
+ props: [
+ {
+ title: '输入框的值',
+ name: 'activeValue',
+ setter: {
+ componentName: 'MixedSetter',
+ isRequired: true,
+ props: {
+ setters: [
+ 'StringSetter',
+ 'NumberSetter',
+ 'VariableSetter',
+ ],
+ },
+ }
+ }
+ ]
+ }
+}
+```
+
+设置后,就会出现“切换设置器”的操作项了
+
+
+
+
+
+#### 开启组件样式设置
+
+
+
+```javascript
+{
+ configure: {
+ // ...,
+ supports: {
+ style: true,
+ },
+ // ...
+ }
+}
+```
+
+#### 设置组件的默认事件
+
+
+
+```javascript
+{
+ configure: {
+ // ...
+ supports: {
+ events: ['onPressEnter', 'onClear', 'onChange', 'onKeyDown', 'onFocus', 'onBlur'],
+ },
+ // ...
+ }
+}
+```
+
+#### 设置 prop 标题的 tip
+
+
+
+```javascript
+{
+ name: 'label',
+ setter: 'StringSetter',
+ title: {
+ label: {
+ type: 'i18n',
+ zh_CN: '标签文本',
+ en_US: 'Label',
+ },
+ tip: {
+ type: 'i18n',
+ zh_CN: '属性:label | 说明:标签文本内容',
+ en_US: 'prop: label | description: label content',
+ },
+ },
+}
+```
+
+#### 配置 prop 对应 setter 在配置面板的展示方式
+
+##### inline
+
+
+
+```javascript
+{
+ configure: {
+ props: [{
+ description: '标签文本',
+ display: 'inline',
+ }]
+ }
+}
+```
+
+##### block
+
+
+
+```javascript
+{
+ configure: {
+ props: [{
+ description: '高级',
+ display: 'block',
+ }]
+ }
+}
+```
+
+##### accordion
+
+
+
+```javascript
+{
+ configure: {
+ props: [{
+ description: '表单项配置',
+ display: 'accordion',
+ }]
+ }
+}
+```
+
+##### entry
+
+
+
+
+
+
+```javascript
+{
+ configure: {
+ props: [{
+ description: '风格与样式',
+ display: 'entry',
+ }]
+ }
+}
+```
+
+##### plain
+
+
+
+```javascript
+{
+ configure: {
+ props: [{
+ description: '返回上级',
+ display: 'plain',
+ }]
+ }
+}
+```
+
+
+### 进阶配置
+
+#### 组件的 children 属性允许传入 ReactNode
+
+例如有一个如下的 Tab 选项卡组件,每个 TabPane 的 children 都是一个组件
+
+
+
+只需要增加 `isContainer` 配置即可
+
+```javascript
+{
+ // ...
+ configure: {
+ // ...
+ component: {
+ // 新增,设置组件为容器组件,可拖入组件
+ isContainer: true,
+ },
+ }
+}
+```
+
+假设我们希望只允许拖拽 Table、Button 等内容放在 TabPane 里。配置白名单 `childWhitelist` 即可
+
+```javascript
+{
+ // ...
+ configure: {
+ // ...
+ component: {
+ isContainer: true,
+ nestingRule: {
+ // 允许拖入的组件白名单
+ childWhitelist: ['Table', 'Button'],
+ // 同理也可以设置该组件允许被拖入哪些父组件里
+ parentWhitelist: ['Tab'],
+ },
+ },
+ },
+}
+```
+#### 组件的非 children 属性允许传入 ReactNode
+
+这就需要使用 `SlotSetter` 开启插槽了,如下面示例,给 Tab 的 title 开启插槽,允许拖拽组件
+
+
+
+```json
+{
+ // ...
+ configure: {
+ isExtend: true,
+ props: [
+ {
+ title: '选项卡标题',
+ name: 'title',
+ setter: {
+ componentName: 'MixedSetter',
+ props: {
+ setters: [
+ 'StringSetter',
+ 'SlotSetter',
+ 'VariableSetter',
+ ],
+ },
+ },
+ },
+ ],
+ },
+}
+```
+
+#### 屏蔽组件在设计器中的操作按钮
+
+正常情况下,组件允许复制:
+
+
+
+如果希望禁止组件的复制行为,我们可以这样做:
+
+
+
+```javascript
+{
+ configure: {
+ component: {
+ disableBehaviors: ['copy'],
+ },
+ },
+}
+```
+
+#### 实现一个 BackwardSetter
+
+
+
+```javascript
+{
+ name: 'back',
+ title: ' ',
+ display: 'plain',
+ setter: BackwardSetter,
+}
+
+// BackwardSetter
+import { SettingTarget, DynamicSetter } from '@alilc/lowcode-types';
+const BackwardSetter: DynamicSetter = (target: SettingTarget) => {
+ return {
+ componentName: (
+
+ ),
+ };
+};
+```
+
+### 高级配置
+
+#### 不展现一个 prop 配置
+
+- 始终隐藏当前 prop
+
+```javascript
+{
+ // 始终隐藏当前 prop 配置
+ condition: () => false,
+}
+```
+
+- 根据其它 prop 的值展示/隐藏当前 prop
+
+```javascript
+{
+ // direction 为 hoz 则展示当前 prop 配置
+ condition: (target) => {
+ return target.getProps().getPropValue('direction') === 'hoz';
+ }
+}
+```
+
+#### props 联动
+
+```javascript
+// 根据当前 prop 的值动态设置其它 prop 的值
+{
+ name: 'labelAlign',
+ // ...
+ extraProps: {
+ setValue: (target, value) => {
+ if (value === 'inset') {
+ target.getProps().setPropValue('labelCol', null);
+ target.getProps().setPropValue('wrapperCol', null);
+ } else if (value === 'left') {
+ target.getProps().setPropValue('labelCol', { fixedSpan: 4 });
+ target.getProps().setPropValue('wrapperCol', null);
+ }
+ return target.getProps().setPropValue('labelAlign', value);
+ },
+ },
+}
+// 根据其它 prop 的值来设置当前 prop 的值
+{
+ name: 'status',
+ // ...
+ extraProps: {
+ getValue: (target) => {
+ const isPreview = target.getProps().getPropValue('isPreview');
+ return isPreview ? 'readonly' : 'editable';
+ }
+ }
+}
+```
+
+#### 动态 setter 配置
+
+可以通过 DynamicSetter 传入的 target 获取一些引擎暴露的数据,例如当前有哪些组件被加载到引擎中,将这个数据作为 SelectSetter 的选项,让用户选择:
+
+```javascript
+{
+ setter: (target) => {
+ return {
+ componentName: 'SelectSetter',
+ props: {
+ options: target.designer.props.componentMetadatas.filter(
+ (item) => item.isFormItemComponent).map(
+ (item) => {
+ return {
+ title: item.title || item.componentName,
+ value: item.componentName,
+ };
+ }
+ ),
+ ),
+ },
+ };
+ }
+}
+```
diff --git a/docs/docs/guide/expand/editor/parts/_category_.json b/docs/docs/guide/expand/editor/parts/_category_.json
new file mode 100644
index 0000000000..005a3caf6c
--- /dev/null
+++ b/docs/docs/guide/expand/editor/parts/_category_.json
@@ -0,0 +1,4 @@
+{
+ "label": "Parts 造物",
+ "position": 1
+}
diff --git a/docs/docs/guide/expand/editor/parts/partsIntro.md b/docs/docs/guide/expand/editor/parts/partsIntro.md
new file mode 100644
index 0000000000..a6fc6e8817
--- /dev/null
+++ b/docs/docs/guide/expand/editor/parts/partsIntro.md
@@ -0,0 +1,18 @@
+---
+title: 介绍
+sidebar_position: 1
+---
+## 介绍
+
+
+
+「Parts·造物」是基于开源低代码引擎打造的次时代物料研发和集成工具,一方面作为低代码引擎搭建低代码平台的一个样板展示开源生态下的各个组件如何集合在一起形成生产力,另一方面也可以生产低代码平台所需的物料。
+
+目前「Parts·造物」主要提供两大产品功能:
+ 1. React 组件导入低代码引擎:通过在线可视化的「物料描述」配置,任意工具开发的 React 组件都可以快速完成对低代码引擎的适配,导入到低代码引擎项目中进行使用。不必额外开发新的组件。
+ 2. 低代码生产组件:通过低代码的形式生产组件,极低上手门槛,提供丰富的原子组件用于组合,完善的调试预览和组件生命周期控制。生产的组件既可以在低代码引擎项目中使用,也可以出码后在普通源码项目中使用。
+
+
+## 联系我们
+
+
diff --git a/docs/docs/guide/expand/editor/parts/partsassets.md b/docs/docs/guide/expand/editor/parts/partsassets.md
new file mode 100644
index 0000000000..00670ecadc
--- /dev/null
+++ b/docs/docs/guide/expand/editor/parts/partsassets.md
@@ -0,0 +1,267 @@
+---
+title: 资产包管理
+sidebar_position: 4
+---
+
+## 介绍
+
+通过前述介绍,相信大家已经了解如何使用「[Parts·造物](https://parts.lowcode-engine.cn/)」来将已有的 React 组件快速接入低代码引擎,以及生产低代码组件。
+
+大家在使用的过程中,可能会希望构建出来的资产包可以后续随时访问下载,或者希望构建资产包时各个组件的版本等信息可以持久化起来并且能够多人维护。
+
+通过「[Parts·造物](https://parts.lowcode-engine.cn/)」的 `资产包` 管理功能帮助大家解决这个问题
+
+
+
+## 新建资产包
+
+首先,我们在 我的资产包 tab 中点击 `新建资产包`
+
+
+- 填写资产包名称
+- 配置资产包管理员,管理员拥有该资产包的所有权限,初始默认为资产包的创建者,还可以添加其他人作为管理员,
+- 配置资产包描述 (可选)
+- 点击 `确定`, 即可完成资产包的创建
+
+接下来需要为资产包添加一个或者多个组件。
+
+## 添加组件
+
+第二步:新建完资产包以后,我们就可以为其添加组件了,如果是新建资产包流程,新建完成之后会自动弹出组件配置的弹窗,当然,你可可以通过点击资产包卡片的方式打开组件配置的弹窗。
+
+
+- 点击弹窗中 `添加组件` 按钮,在弹出的组件选择面板中,选中需要添加的组件并点击 `下一步`。
+ 
+- 进入组件版本以及描述协议版本选择界面,选择所需要的正确版本,点击 `安装` 即可完成一个组件的添加。
+ 
+
+## 构建资产包
+
+添加完组件以后就点击 `保存并构建资产包` 进入资产包构建配置弹窗
+
+
+- `开启缓存` : 可充分利用之前的构建结果缓存来加速资产包的生成,我们会将每个组件的构建结果以 包名和版本号为 key 进行缓存。
+- `任务描述` : 当前构建任务的一些描述信息。
+
+点击 `确认` 按钮 会自动跳转到当前资产包的构建历史界面:
+
+构建历史界面会显示当前资产包所有的构建历史记录,表格状态栏展示了构建的状态:`成功`,`失败`,`正在运行` 三种状态,操作列可以在构建成功时复制或者下载资产包结果
+
+## 使用资产包
+你可以在 [lowcode-demo](https://github.com/alibaba/lowcode-demo) 中直接引用,可直接替换 demo 中原来的资产包文件:
+例如,在 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中,直接用你的资产包文件替换文件[assets.json](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/services/assets.json),即可快速使用自己的物料了。
+
+### 在编辑器中使用资产包
+在使用含有低代码组件的资产包注意 注意引擎版本必须大于等于 `1.1.0-beta.9`。
+然后直接替换 [lowcode-demo](https://github.com/alibaba/lowcode-demo) demo 中的 `assets.json` 文件即可。
+
+### 在预览中使用资产包
+在预览中使用资产包的整体思路是从 `资产包` 中提取并转换出 `ReactRenderer` 渲染所需要的 react 组件列表 (`components` 参数),然后将 `schema` 以及 `components` 传入到 `ReactRenderer` 中进行渲染,需要注意的是,在 `资产包` 的转换过程中,我们也需要将 `低代码组件` 转换成 react 组件,具体逻辑可以参考下 [demo-lowcode-component](https://github.com/alibaba/lowcode-demo/tree/main/demo-lowcode-component) 中 `src/parse-assets.ts` 文件的实现。
+基于资产包进行预览的整体逻辑如下: [详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/preview.tsx):
+```ts
+import ReactDOM from 'react-dom';
+import React, { useState } from 'react';
+import { Loading } from '@alifd/next';
+import ReactRenderer from '@alilc/lowcode-react-renderer';
+import { createFetchHandler } from '@alilc/lowcode-datasource-fetch-handler';
+import {
+ getProjectSchemaFromLocalStorage,
+} from './services/mockService';
+import assets from './services/assets.json';
+import { parseAssets } from './parse-assets';
+
+const getScenarioName = function () {
+ if (location.search) {
+ return new URLSearchParams(location.search.slice(1)).get('scenarioName') || 'index';
+ }
+ return 'index';
+};
+
+const SamplePreview = () => {
+ const [data, setData] = useState({});
+ async function init() {
+ const scenarioName = getScenarioName();
+ const projectSchema = getProjectSchemaFromLocalStorage(scenarioName);
+ const { componentsMap: componentsMapArray, componentsTree } = projectSchema;
+ const schema = componentsTree[0];
+ const componentsMap: any = {};
+ componentsMapArray.forEach((component: any) => {
+ componentsMap[component.componentName] = component;
+ });
+
+ // 特别提醒重点注意!!!:从资产包中解析出所有的 react 组件列表
+ const { components } = await parseAssets(assets);
+
+ setData({
+ schema,
+ components,
+ });
+ }
+
+ const { schema, components } = data;
+
+ if (!schema || !components) {
+ init();
+ return ;
+ }
+
+ return (
+
+
+
+ );
+};
+
+ReactDOM.render(, document.getElementById('ice-container'));
+```
+
+从资产包中解析 react 组件列表的逻辑如下,[详见](https://github.com/alibaba/lowcode-demo/blob/main/demo-lowcode-component/src/parse-assets.ts):
+```ts
+import { ComponentDescription, ComponentSchema, RemoteComponentDescription } from '@alilc/lowcode-types';
+import { buildComponents, AssetsJson, AssetLoader } from '@alilc/lowcode-utils';
+import ReactRenderer from '@alilc/lowcode-react-renderer';
+import { injectComponents } from '@alilc/lowcode-plugin-inject';
+import React, { createElement } from 'react';
+
+export async function parseAssets(assets: AssetsJson) {
+ const { components: rawComponents, packages } = assets;
+ const libraryAsset = [];
+ const libraryMap = {};
+ const packagesMap = {};
+ packages.forEach(pkg => {
+ const { package: _package, library, urls, renderUrls, id } = pkg;
+ if (_package) {
+ libraryMap[id || _package] = library;
+ }
+ packagesMap[id || _package] = pkg;
+ if (renderUrls) {
+ libraryAsset.push(renderUrls);
+ } else if (urls) {
+ libraryAsset.push(urls);
+ }
+ });
+ const assetLoader = new AssetLoader();
+ await assetLoader.load(libraryAsset);
+ let newComponents = rawComponents;
+ if (rawComponents && rawComponents.length) {
+ const componentDescriptions: ComponentDescription[] = [];
+ const remoteComponentDescriptions: RemoteComponentDescription[] = [];
+ rawComponents.forEach((component: any) => {
+ if (!component) {
+ return;
+ }
+ if (component.exportName && component.url) {
+ remoteComponentDescriptions.push(component);
+ } else {
+ componentDescriptions.push(component);
+ }
+ });
+ newComponents = [...componentDescriptions];
+
+ // 如果有远程组件描述协议,则自动加载并补充到资产包中,同时出发 designer.incrementalAssetsReady 通知组件面板更新数据
+ if (remoteComponentDescriptions && remoteComponentDescriptions.length) {
+ await Promise.all(
+ remoteComponentDescriptions.map(async (component: any) => {
+ const { exportName, url, npm } = component;
+ await (new AssetLoader()).load(url);
+ function setAssetsComponent(component: any, extraNpmInfo: any = {}) {
+ const components = component.components;
+ if (Array.isArray(components)) {
+ components.forEach(d => {
+ newComponents = newComponents.concat({
+ npm: {
+ ...npm,
+ ...extraNpmInfo,
+ },
+ ...d,
+ } || []);
+ });
+ return;
+ }
+ newComponents = newComponents.concat({
+ npm: {
+ ...npm,
+ ...extraNpmInfo,
+ },
+ ...component.components,
+ } || []);
+ }
+
+ function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') {
+ value.forEach((d: any, i: number) => {
+ const exportName = [preExportName, i.toString()].filter(d => !!d).join('.');
+ const subName = [preSubName, i.toString()].filter(d => !!d).join('.');
+ Array.isArray(d) ? setArrayAssets(d, exportName, subName) : setAssetsComponent(d, {
+ exportName,
+ subName,
+ });
+ });
+ }
+ if (window[exportName]) {
+ if (Array.isArray(window[exportName])) {
+ setArrayAssets(window[exportName] as any);
+ } else {
+ setAssetsComponent(window[exportName] as any);
+ }
+ }
+ return window[exportName];
+ }),
+ );
+ }
+ }
+ const lowcodeComponentsArray = [];
+ const proCodeComponentsMap = newComponents.reduce((acc, cur) => {
+ if ((cur.devMode || '').toLowerCase() === 'lowcode') {
+ lowcodeComponentsArray.push(cur);
+ } else {
+ acc[cur.componentName] = {
+ ...(cur.reference || cur.npm),
+ componentName: cur.componentName,
+ };
+ }
+ return acc;
+ }, {})
+
+ function genLowCodeComponentsMap(components) {
+ const lowcodeComponentsMap = {};
+ lowcodeComponentsArray.forEach((lowcode) => {
+ const id = lowcode.reference?.id;
+ const schema = packagesMap[id]?.schema;
+ const comp = genLowcodeComp(schema, {...components, ...lowcodeComponentsMap});
+ lowcodeComponentsMap[lowcode.componentName] = comp;
+ });
+ return lowcodeComponentsMap;
+ }
+ let components = await injectComponents(buildComponents(libraryMap, proCodeComponentsMap));
+ const lowCodeComponents = genLowCodeComponentsMap(components);
+ return {
+ components: { ...components, ...lowCodeComponents }
+ }
+}
+
+function genLowcodeComp(schema: ComponentSchema, components: any) {
+ return class LowcodeComp extends React.Component {
+ render(): React.ReactNode {
+ return createElement(ReactRenderer, {
+ ...this.props,
+ schema,
+ components,
+ designMode: '',
+ });
+ }
+ };
+}
+```
+## 联系我们
+
+
\ No newline at end of file
diff --git a/docs/docs/guide/expand/editor/parts/partslcc.md b/docs/docs/guide/expand/editor/parts/partslcc.md
new file mode 100644
index 0000000000..4d24b72f3a
--- /dev/null
+++ b/docs/docs/guide/expand/editor/parts/partslcc.md
@@ -0,0 +1,92 @@
+---
+title: 低代码组件
+sidebar_position: 2
+---
+## 什么是低代码组件
+我们先了解一下什么是低代码组件,为什么要用低代码组件。
+
+低代码组件是通过可视化的方式生产的组件,这些组件既可以用于低代码搭建体系,也可以用于 ProCode 开发体系(后续迭代)。
+
+那么为什么我们要使用低代码的形式来开发组件:
+* 首先:轻快,低代码组件只需通过浏览器秒级完成初始化工作,不需要 ProCode 繁重的环境准备;环境一致(低代码环境),同时能够保证物料的开发环境和真实的运行环境是一致的,不会存在开发和运行环境不一致的问题。
+* 其次:通用能力可视化方式抽象,提升研发效能,比如获取远程数据、视图开发、依赖管理、生命周期、事件绑定等功能。
+
+低代码组件不是用来替代 ProCode 的开发方式,而是让开发者可以从 ProCode 中重复的工作脱离出来,抽象更多业务垂直的能力,从而起到提效的作用。
+
+## 创建组件
+
+环境准备:我们可以通过 Parts 提供的通用[低代码组件开发环境](https://parts.lowcode-engine.cn/material#/)开发。
+
+点击开发新组件 --> 填写组件标题 --> 填写组件名称 --> 点击确定,完成组件创建工作。
+
+
+
+## 组件开发
+
+一张图速览低代码组件开发的功能模块,其中大部分功能可以参考[低代码引擎文档](https://lowcode-engine.cn/site/docs/guide/quickStart/intro)。
+
+
+
+### 依赖管理
+
+依赖管理用于管理低代码组件本身的依赖(类似于 dependencies)。步骤:点击添加组件 --> 选择安装的组件 --> 保存并构建 (需要等待几分钟构建)。
+
+
+
+### 属性定义
+
+用于定义组件接收外部传入的 propTypes,组件内部可以通过this.props.${属性名称}的方式获取属性值。
+
+属性定义前建议先阅读 [物料描述详解](https://lowcode-engine.cn/site/docs/guide/expand/editor/metaSpec)、[预置设置器](https://lowcode-engine.cn/site/docs/guide/appendix/setters)。
+
+
+
+
+
+### 生命周期
+
+低代码组件的开发支持 componentDidMount、componentDidUpdate、componentDidCatch、componentWillUnmount 几个生命周期
+
+
+
+### 组件调试
+
+我们提供了一套线上实时调试的方案,只需点击右上角的调试按钮,就能自动创建一个低代码应用,在这个应用中可以实时调试当前的低代码组件。
+
+
+
+在低代码应用中使用,组件面板 --> 低代码组件,找到对应的低代码组件拖入画布即可。
+
+
+
+### 组件发布
+
+同时我们提供了组件发布的功能,用于组件版本管理,点击右上角的发布按钮即可发布组件
+
+
+
+## 组件使用
+
+组件的消费是通过资产包来管理的,详情请参考 [资产包管理](./partsassets)。
+
+## 组件导出
+
+开发好的低代码组件可以导出成为 React 组件,脱离低代码引擎独立使用。同时导出功能也为您的组件留出一份备份,您可以放心使用本产品的服务,而不用担心万一出现的不能服务的场景。
+
+在物料列表页面,低代码组件会有一个导出的动作。
+
+
+
+点击导出后,就会开启导出低代码组件的过程。这个过程持续 10s+,导出完成后会为您自动下载对应的 zip 包。
+
+
+
+zip 包解压后可以看到一个完整的组件脚手架工程,您可以在这个工程里继续开发调试,或者发布到合适的 npm 源中。
+
+
+
+注意:目前导出功能暂不支持 低代码组件嵌套。
+
+## 联系我们
+
+
\ No newline at end of file
diff --git a/docs/docs/guide/expand/editor/parts/prototype.md b/docs/docs/guide/expand/editor/parts/prototype.md
new file mode 100644
index 0000000000..b90728f657
--- /dev/null
+++ b/docs/docs/guide/expand/editor/parts/prototype.md
@@ -0,0 +1,121 @@
+---
+title: React 组件导入
+sidebar_position: 3
+---
+## 介绍
+大家在使用[低代码引擎](https://lowcode-engine.cn/)构建低代码应用平台时,遇到的一个主要问题是如何让已有的 React 组件能够快速低成本地接入进来。这个问题拆解下来主要包括两个子问题:
+1. 如何给已有组件[配置物料描述](/site/docs/specs/material-spec),
+2. 如何构建出一个低代码引擎能够识别的资产包 (Assets)。
+
+我们的产品「[Parts·造物](https://parts.lowcode-engine.cn/)」可以帮助大家解决这个问题。我们通过在线可视化的方式完成物料描述配置,并且提供一键打包的功能生成引擎可以识别的资产包。
+
+## 导入物料
+首先,我们需要在 [物料管理](/site/docs/specs/material-spec) 页面导入我们需要进行在线物料描述配置的物料。
+
+
+- 点击列表左上方的 导入已有物料 按钮
+- 在弹框中输入 npm 包名
+- 点击 获取包信息 按钮,获取 npm 包基本信息
+- 点击确定,导入成功
+
+
+## 配置管理
+第二步:物料导入以后,我们就可以为导入的物料新增[物料描述配置](/site/docs/specs/material-spec),点击右侧的组件配置开始配置。
+
+
+### 新增配置
+
+- 点击配置管理右上角的 新增配置
+ - 选择组件的版本号
+ - 填写组件路径,一般和 npm 包的 package.json 里的 main 字段相同(如果填写错误,后面会渲染不出来)
+ - 描述字段用于给这份配置增加一些备注信息。
+
+
+
+为了降低配置成本,第一次新增配置的时候会自动解析组件代码,生成一份初始化组件物料描述。所以需要等待片刻,用于代码解析。解析完成后,点击配置按钮即可进入在线配置界面。
+
+
+
+### 组件描述配置
+操作界面如下,接下来讲具体的配置流程
+
+
+
+#### 新增组件
+
+如果新增配置的过程中,代码自动解析失败或者解析出来的组件列表不满足开发要求,我们可以点击左侧组件列表插件 新增 按钮,添加新的组件,具体的字段描述可以参考提示内容,以 [react-color](https://github.com/casesandberg/react-color) 为例:
+
+
+
+
+#### 给组件增加物料描述
+
+- 打开左侧 Setter 面板
+- 按照组件的属性拖入需要 Setter 类型(如图中组件的 width 属性,拖入数字 Setter)
+- 各种 Setter 的介绍可以参看这篇文档:[预置设置器列表](/site/docs/guide/appendix/setters)
+- 配置属性的基本信息(如图所示)
+- 配置完成后点击右上角的保存
+
+
+
+
+
+#### 高级配置(属性联动)
+
+举个栗子:如图所示,如果期望“设置器”这个配置项的值“被修改”的时候,下面的“默认值”跟着变化。
+
+
+
+如何使用
+
+组件的属性配置目前支持 3 个基本的联动函数:
+
+- 显示状态:返回 true | false,如果返回 true,表示组件配置显示,否则配置时不显示
+- 获取值:当调用该配置节点的 getValue 方法时触发的方法
+- 值变化:当调用该配置节点的 setValue 方法时触发的方法
+
+
+
+方法的第一个参数都是当前配置节点的对象,常用到的有以下几个:
+
+- getValue(): 获取当前节点的值,如果当前节点是子节点的话,否则为 undefined
+- setValue(): 设置当前节点的值,如果当前节点是子节点的话
+- parent: 当前节点的父节点
+- getPropValue(propName): 父节点获取子节点的属性值,propName 为子节点的属性名称
+- setPropValue(propName, value): 父节点设置子节点的属性值,propName 为子节点的属性名称,value 为设置的值
+- getConfig: 获取当前节点的配置,如 title、setter 等
+
+
+#### 调试物料描述
+
+点击右上角的预览按钮,开始调试我们刚刚配置的属性,如果是组件的首次预览,会有一段组件构建的过程(构建出 umd 包的过程),构建完成后就可以调试我们的配置了。
+
+
+
+#### 发布物料描述
+物料描述调试没问题后,就可以到项目中去使用了,使用前需要先发布物料描述
+
+- 点击右上角的发布按钮
+- 选择需要发布的组件
+- 点击确定发布完成
+
+
+## 资产包
+第三步:物料描述发布完成后,接下来我们就需要构建出可用的资产包用于低代码应用中。
+
+#### 资产包构建
+有两种方式可以构建资产包:
+- 一种是通过 [`我的资产包`] 资产包管理模块进行整个资产包生命周期的管理,当然也包括资产包的构建,可参考 [资产包管理](./partsassets)
+- 一种是通过 [`我的物料`] 组件物料管理模块的 `资产包构建` 进行构建, 具体操作如下:
+
+ - 选择需要构建的组件
+ - 点击构建资产包按钮
+ - 选择刚刚的物料描述配置
+ - 开始构建,构建完成后你将得到一份 json 文件(里面包含了物料描述和 umd 包),就可以到项目中使用了
+
+#### 资产包使用
+详情请参考 [资产包管理](./partsassets#使用资产包)
+
+## 联系我们
+
+
diff --git a/docs/docs/guide/expand/editor/pluginContextMenu.md b/docs/docs/guide/expand/editor/pluginContextMenu.md
new file mode 100644
index 0000000000..962c913e7e
--- /dev/null
+++ b/docs/docs/guide/expand/editor/pluginContextMenu.md
@@ -0,0 +1,82 @@
+---
+title: 插件扩展 - 编排扩展
+sidebar_position: 6
+---
+
+## 场景一:扩展选中节点操作项
+
+### 增加节点操作项
+
+
+选中节点后,在选中框的右上角有操作按钮,编排模块默认实现了查看组件直系父节点、复制节点和删除节点按钮外,还可以通过相关 API 来扩展更多操作,如下代码:
+
+```typescript
+import { plugins } from '@alilc/lowcode-engine';
+import { IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types';
+import { Icon, Message } from '@alifd/next';
+
+const addHelloAction = (ctx: IPublicModelPluginContext) => {
+ return {
+ async init() {
+ ctx.material.addBuiltinComponentAction({
+ name: 'hello',
+ content: {
+ icon: ,
+ title: 'hello',
+ action(node: IPublicModelNode) {
+ Message.show('Welcome to Low-Code engine');
+ },
+ },
+ condition: (node: IPublicModelNode) => {
+ return node.componentMeta.componentName === 'NextTable';
+ },
+ important: true,
+ });
+ },
+ };
+};
+addHelloAction.pluginName = 'addHelloAction';
+await plugins.register(addHelloAction);
+```
+
+**_效果如下:_**
+
+
+
+具体 API 参考:[API 文档](/site/docs/api/material#addbuiltincomponentaction)
+### 删除节点操作项
+
+```typescript
+import { plugins } from '@alilc/lowcode-engine';
+import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+
+const removeCopyAction = (ctx: IPublicModelPluginContext) => {
+ return {
+ async init() {
+ ctx.material.removeBuiltinComponentAction('copy');
+ }
+ }
+};
+removeCopyAction.pluginName = 'removeCopyAction';
+await plugins.register(removeCopyAction);
+```
+
+**_效果如下:_**
+
+
+
+具体 API 参考:[API 文档](/site/docs/api/material#removebuiltincomponentaction)
+
+## 实际案例
+
+### 区块管理
+
+- 仓库地址:[https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins)
+- 具体代码:[https://github.com/alibaba/lowcode-plugins/tree/main/packages/action-block](https://github.com/alibaba/lowcode-plugins/tree/main/packages/action-block)
+- 直播回放:
+ - [低代码引擎项目实战 (9)-区块管理 (1)-保存为区块](https://www.bilibili.com/video/BV1YF411M7RK/)
+ - [低代码引擎项目实战 (10)-区块管理 - 区块面板](https://www.bilibili.com/video/BV1FB4y1S7tu/)
+ - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - ICON 优化](https://www.bilibili.com/video/BV1zr4y1H7Km/)
+ - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 自动截图](https://www.bilibili.com/video/BV1GZ4y117VH/)
+ - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 样式优化](https://www.bilibili.com/video/BV1Pi4y1S7ZT/)
+ - [阿里低代码引擎项目实战 (12)-区块管理 (完结)-给引擎插件提个 PR](https://www.bilibili.com/video/BV1hB4y1277o/)
diff --git a/docs/docs/guide/expand/editor/pluginWidget.md b/docs/docs/guide/expand/editor/pluginWidget.md
new file mode 100644
index 0000000000..06125575f6
--- /dev/null
+++ b/docs/docs/guide/expand/editor/pluginWidget.md
@@ -0,0 +1,214 @@
+---
+title: 插件扩展 - 面板扩展
+sidebar_position: 5
+---
+
+## 插件简述
+
+插件功能赋予低代码引擎更高的灵活性,低代码引擎的生态提供了一些官方的插件,但是无法满足所有人的需求,所以提供了强大的插件定制功能。
+
+通过定制插件,在和低代码引擎解耦的基础上,我们可以和引擎核心模块进行交互,从而满足多样化的功能。不仅可以自定义插件的 UI,还可以实现一些非 UI 的逻辑:
+
+1. 调用编辑器框架提供的 API 进行编辑器操作或者 schema 操作;
+2. 通过插件类的生命周期函数实现一些插件初始化的逻辑;
+3. 通过实现监听编辑器内的消息实现特定的切片逻辑(例如面板打开、面板关闭等);
+
+> 本文仅介绍面板层面的扩展,编辑器插件层面的扩展可以参考 ["插件扩展 - 编排扩展"](./pluginContextMenu.md) 章节。
+
+## 注册插件 API
+
+```typescript
+import { plugins } from '@alilc/lowcode-engine';
+import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+
+const pluginA = (ctx: IPublicModelPluginContext, options: any) => {
+ return {
+ init() {
+ console.log(options.key);
+ // 往引擎增加面板
+ ctx.skeleton.add({
+ // area 配置见下方说明
+ area: 'leftArea',
+ // type 配置见下方说明
+ type: 'PanelDock',
+ content: demo
,
+ });
+ ctx.logger.log('打个日志');
+ },
+ destroy() {
+ console.log('我被销毁了~');
+ },
+ };
+};
+
+pluginA.pluginName = 'pluginA';
+
+plugins.register(pluginA, { key: 'test' });
+```
+
+> 如果您想了解抽取出来的插件如何封装成为一个 npm 包并提供给社区,可以参考[“低代码生态脚手架 & 调试机制”](./cli)章节。
+
+## 面板插件配置说明
+
+面板插件是作用于设计器的,主要是通过按钮、图标等展示在设计器的骨架中。设计器的骨架我们分为下面的几个区域,而我们的插件大多数都是作用于这几个区域的。
+
+
+
+
+
+### 展示区域 area
+
+#### topArea
+
+展示在设计器的顶部区域,常见的相关区域的插件主要是:、
+
+1. 注册设计器 Logo;
+2. 设计器操作回退和撤销按钮;
+3. 全局操作按钮,例如:保存、预览等;
+
+#### leftArea
+
+左侧区域的展示形式大多数是 Icon 和对应的面板,通过点击 Icon 可以展示对应的面板并隐藏其他的面板。
+
+该区域相关插件的主要有:
+
+1. 大纲树展示,展示该设计器设计页面的大纲。
+2. 组件库,展示注册到设计器中的组件,点击之后,可以从组件库面板中拖拽到设计器的画布中。
+3. 数据源面板
+4. JS 等代码面板。
+
+可以发现,这个区域的面板大多数操作时是不需要同时并存的,且交互比较复杂的,需要一个更整块的区域来进行操作。
+
+#### centerArea
+
+画布区域,由于画布大多数是展示作用,所以一般扩展的种类比较少。常见的扩展有:
+
+1. 画布大小修改
+2. 物料选中扩展区域修改
+
+#### rightArea
+
+右侧区域,常用于组件的配置。常见的扩展有:统一处理组件的配置项,例如统一删除某一个配置项,统一添加某一个配置项的。
+
+#### toolbar
+
+跟 topArea 类似,按需放置面板插件~
+
+### 展示形式 type
+
+#### PanelDock
+
+PanelDock 是以面板的形式展示在设计器的左侧区域的。其中主要有两个部分组成,一个是图标,一个是面板。当点击图标时可以控制面板的显示和隐藏。
+
+下图是组件库插件的展示效果。
+
+
+
+其中右上角可以进行固定,可以对弹出的宽度做设定
+
+接入可以参考代码
+
+```javascript
+import { skeleton } from '@alilc/lowcode-engine';
+
+skeleton.add({
+ area: 'leftArea', // 插件区域
+ type: 'PanelDock', // 插件类型,弹出面板
+ name: 'sourceEditor',
+ content: SourceEditor, // 插件组件实例
+ props: {
+ align: "left",
+ icon: "wenjian",
+ description: "JS 面板",
+ },
+ panelProps: {
+ floatable: true, // 是否可浮动
+ height: 300,
+ hideTitleBar: false,
+ maxHeight: 800,
+ maxWidth: 1200,
+ title: "JS 面板",
+ width: 600,
+ },
+});
+```
+
+#### Widget
+
+Widget 形式是直接渲染在当前编辑器的对应位置上。如 demo 中在设计器顶部的所有组件都是这种展现形式。
+
+
+
+接入可以参考代码:
+
+```javascript
+import { skeleton } from '@alilc/lowcode-engine';
+// 注册 logo 面板
+skeleton.add({
+ area: 'topArea',
+ type: 'Widget',
+ name: 'logo',
+ content: Logo, // Widget 组件实例
+ contentProps: { // Widget 插件 props
+ logo:
+ "https://img.alicdn.com/tfs/TB1_SocGkT2gK0jSZFkXXcIQFXa-66-66.png",
+ href: "/",
+ },
+ props: {
+ align: 'left',
+ width: 100,
+ },
+});
+```
+
+#### Dock
+
+一个图标的表现形式,可以用于语言切换、跳转到外部链接、打开一个 widget 等场景。
+
+```javascript
+import { skeleton } from '@alilc/lowcode-engine';
+
+skeleton.add({
+ area: 'leftArea',
+ type: 'Dock',
+ name: 'opener',
+ props: {
+ icon: Icon, // Icon 组件实例
+ align: 'bottom',
+ onClick: function () {
+ // 打开外部链接
+ window.open('https://lowcode-engine.cn');
+ // 显示 widget
+ skeleton.showWidget('xxx');
+ }
+ }
+});
+```
+
+#### Panel
+
+一般不建议单独使用,通过 PanelDock 使用~
+
+## 实际案例
+
+### 页面管理面板
+
+- 仓库地址:[https://github.com/mark-ck/lowcode-portal](https://github.com/mark-ck/lowcode-portal)
+- 具体代码:[https://github.com/mark-ck/lowcode-portal/blob/master/src/plugins/pages-plugin/index.tsx](https://github.com/mark-ck/lowcode-portal/blob/master/src/plugins/pages-plugin/index.tsx)
+- 直播回放:
+ - [低代码引擎项目实战 (4)-自定义插件 - 页面管理](https://www.bilibili.com/video/BV17a411i73f/)
+ - [低代码引擎项目实战 (4)-自定义插件 - 页面管理 - 后端](https://www.bilibili.com/video/BV1uZ4y1U7Ly/)
+ - [低代码引擎项目实战 (4)-自定义插件 - 页面管理 - 前端](https://www.bilibili.com/video/BV1Yq4y1a74P/)
+ - [低代码引擎项目实战 (4)-自定义插件 - 页面管理 - 完结](https://www.bilibili.com/video/BV13Y4y1e7EV/)
+
+### 区块面板
+
+- 仓库地址:[https://github.com/alibaba/lowcode-plugins](https://github.com/alibaba/lowcode-plugins)
+- 具体代码:[https://github.com/alibaba/lowcode-plugins/tree/main/packages/plugin-block](https://github.com/alibaba/lowcode-plugins/tree/main/packages/plugin-block)
+- 直播回放:
+ - [低代码引擎项目实战 (9)-区块管理 (1)-保存为区块](https://www.bilibili.com/video/BV1YF411M7RK/)
+ - [低代码引擎项目实战 (10)-区块管理 - 区块面板](https://www.bilibili.com/video/BV1FB4y1S7tu/)
+ - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - ICON 优化](https://www.bilibili.com/video/BV1zr4y1H7Km/)
+ - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 自动截图](https://www.bilibili.com/video/BV1GZ4y117VH/)
+ - [阿里巴巴低代码引擎项目实战 (11)-区块管理 - 样式优化](https://www.bilibili.com/video/BV1Pi4y1S7ZT/)
+ - [阿里低代码引擎项目实战 (12)-区块管理 (完结)-给引擎插件提个 PR](https://www.bilibili.com/video/BV1hB4y1277o/)
diff --git a/docs/docs/guide/expand/editor/setter.md b/docs/docs/guide/expand/editor/setter.md
new file mode 100644
index 0000000000..4f0e0219fc
--- /dev/null
+++ b/docs/docs/guide/expand/editor/setter.md
@@ -0,0 +1,241 @@
+---
+title: 设置器扩展
+sidebar_position: 7
+---
+## 设置器简述
+
+设置器主要用于低代码组件属性值的设置,顾名思义叫"设置器",又称为 Setter。由于组件的属性有各种类型,需要有与之对应的设置器支持,每一个设置器对应一个值的类型。
+
+### 设计器展示位置
+
+设置器展示在编辑器的右边区域,如下图:
+
+
+
+其中包含四类设置器:
+
+- 属性:展示该物料常规的属性
+- 样式:展示该物料样式的属性
+- 事件:如果该物料有声明事件,则会出现事件面板,用于绑定事件。
+- 高级:两个逻辑相关的属性,**条件渲染**和**循环**
+
+### 设置器类型
+
+上述区域中是有多项设置器的,对于一个组件来说,每一项配置都对应一个设置器,比如我们的配置是一个文本,我们需要的是文本设置器,我们需要配置的是数字,我们需要的就是数字设置器。
+下图中的标题和按钮类型配置就分别是文本设置器和下拉框设置器。
+
+
+
+我们提供了常用的设置器作为内置设置器,也提供了定制能力帮助大家开发特定需求的设置器。
+
+## 为物料配置设置器
+
+我们提供了[常用的设置器](/site/docs/guide/appendix/setters)作为内置设置器。
+
+我们可以将目标组件的属性值类型值配置到物料资源配置文件中:
+
+```json
+{
+ "componentName": "Message",
+ "title": "Message",
+ "configure": {
+ "props": [
+ {
+ "name": "type",
+ "setter": "InputSetter"
+ }
+ ]
+ }
+}
+```
+
+props 字段是入料模块扫描自动填入的类型,用户可以通过 configure 节点进行配置通过 override 节点对属性的声明重新定义,setter 就是注册在引擎中的 setter。
+
+为物料配置引擎内置的 setter 时,均可以使用对应 setter 的高级功能,对应功能参考“全部内置设置器”章节下的对应 setter 文章。
+
+### 对高级功能的配置如下:
+
+例如我们需要在 NumberSetter 中配置 units 属性,可以在 asset.json 中声明。
+
+```json
+"configure": {
+ "component": {
+ "isContainer": true,
+ "nestingRule": {
+ "parentWhitelist": [
+ "NextP"
+ ]
+ }
+ },
+ "props": [
+ {
+ "name": "width",
+ "title": "宽度",
+ "initialValue": "auto",
+ "defaultValue": "auto",
+ "condition": {
+ "type": "JSFunction",
+ "value": "() => false"
+ },
+ "setter": {
+ "componentName": "NumberSetter",
+ "props": {
+ "units": [
+ {
+ "type": "px",
+ "list": true
+ },
+ {
+ "type": "%",
+ "list": true
+ }
+ ]
+ }
+ }
+ },
+ ],
+ "supports": {
+ "style": true
+ }
+},
+```
+
+## 自定义设置器
+### 编写 AltStringSetter
+
+我们编写一个简单的 Setter,它的功能如下:
+
+
+
+**代码如下:**
+```tsx
+import * as React from "react";
+import { Input } from "@alifd/next";
+import "./index.scss";
+
+interface AltStringSetterProps {
+ // 当前值
+ value: string;
+ // 默认值
+ defaultValue: string;
+ // setter 唯一输出
+ onChange: (val: string) => void;
+ // AltStringSetter 特殊配置
+ placeholder: string;
+}
+
+export default class AltStringSetter extends React.PureComponent {
+ // 声明 Setter 的 title
+ static displayName = 'AltStringSetter';
+
+ componentDidMount() {
+ const { onChange, value, defaultValue } = this.props;
+ if (value == undefined && defaultValue) {
+ onChange(defaultValue);
+ }
+ }
+
+ render() {
+ const { onChange, value, placeholder } = this.props;
+ return (
+ onChange(val)}
+ >
+ );
+ }
+}
+```
+
+#### setter 和 setter/plugin 之间的联动
+
+我们采用 emit 来进行相互之前的通信,首先我们在 A setter 中进行事件注册:
+
+```javascript
+import { event } from '@alilc/lowcode-engine';
+
+componentDidMount() {
+ // 这里由于面板上会有多个 setter,这里我用 field.id 来标记 setter 名
+ this.emitEventName = `${SETTER_NAME}-${this.props.field.id}`;
+ event.on(`${this.emitEventName}.bindEvent`, this.bindEvent);
+}
+
+bindEvent = (eventName) => {
+ // do someting
+}
+
+componentWillUnmount() {
+ // setter 是以实例为单位的,每个 setter 注销的时候需要把事件也注销掉,避免事件池过多
+ event.off(`${this.emitEventName}.bindEvent`, this.bindEvent);
+}
+```
+
+在 B setter 中触发事件,来完成通信:
+
+```javascript
+import { event } from '@alilc/lowcode-engine';
+
+bindFunction = () => {
+ const { field, value } = this.props;
+ // 这里展示的和插件进行通信,事件规则是插件名 + 方法
+ event.emit('eventBindDialog.openDialog', field.name, this.emitEventName);
+}
+```
+
+#### 修改同级 props 的其他属性值
+
+setter 本身只影响其中一个 props 的值,如果需要影响其他组件的 props 的值,需要使用 field 的 props:
+
+```javascript
+bindFunction = () => {
+ const { field, value } = this.props;
+ const propsField = field.parent;
+ // 获取同级其他属性 showJump 的值
+ const otherValue = propsField.getPropValue('showJump');
+ // set 同级其他属性 showJump 的值
+ propsField.setPropValue('showJump', false);
+}
+```
+
+### 注册 AltStringSetter
+
+我们需要在低代码引擎中注册 Setter,这样就可以通过 AltStringSetter 的名字在物料中使用了。
+
+```typescript
+import AltStringSetter from './AltStringSetter';
+const registerSetter = window.AliLowCodeEngine.setters.registerSetter;
+registerSetter('AltStringSetter', AltStringSetter);
+```
+
+### 物料中使用
+
+我们需要将目标组件的属性值类型值配置到物料资源配置文件中,其中核心配置如下:
+
+```json
+{
+ "props": [
+ {
+ "name": "type",
+ "setter": "AltStringSetter"
+ }
+ ]
+}
+```
+
+在物料中的相关配置如下:
+
+```json
+{
+ "componentName": "Message",
+ "title": "Message",
+ "configure": {
+ "props": [
+ {
+ "name": "type",
+ "setter": "AltStringSetter"
+ }
+ ]
+ }
+}
+```
\ No newline at end of file
diff --git a/docs/docs/guide/expand/editor/summary.md b/docs/docs/guide/expand/editor/summary.md
new file mode 100644
index 0000000000..814340f3d3
--- /dev/null
+++ b/docs/docs/guide/expand/editor/summary.md
@@ -0,0 +1,92 @@
+---
+title: 编辑态扩展简述
+sidebar_position: 0
+---
+## 扩展点简述
+
+我们可以从 Demo 的项目中看到页面中有很多的区块:
+
+这些功能点背后都是可扩展项目,如下图所示:
+
+
+- 插件定制:可以配置低代码编辑器的功能和面板
+- 物料定制:可以配置能够拖入的物料
+- 操作辅助区定制:可以配置编辑器画布中的操作辅助区功能
+- 设置器定制:可以配置编辑器中组件的配置表单
+
+我们从可扩展项目的视角,可以把低代码引擎架构理解为下图:
+
+
+(注:引擎内核中大量数据交互的细节被简化,这张图仅仅强调编辑器和外部扩展的交互)
+
+## 配置扩展点
+
+### 配置物料
+通过配置注入物料,这里的配置是物料中心根据物料资产包协议生成的,后面“物料扩展”章节会有详细说明。
+```typescript
+import { material } from '@alilc/lowcode-engine';
+// 假设您已把物料配置在本地
+import assets from './assets.json';
+
+// 静态加载 assets
+material.setAssets(assets);
+```
+
+也可以通过异步加载物料中心上的物料。
+```typescript
+import { material, plugins } from '@alilc/lowcode-engine';
+import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+
+// 动态加载 assets
+plugins.register((ctx: IPublicModelPluginContext) => {
+ return {
+ name: 'ext-assets',
+ async init() {
+ try {
+ // 将下述链接替换为您的物料即可。无论是通过 utils 从物料中心引入,还是通过其他途径如直接引入物料描述
+ const res = await window.fetch('https://fusion.alicdn.com/assets/default@0.1.95/assets.json')
+ const assets = await res.text()
+ material.setAssets(assets)
+ } catch (err) {
+ console.error(err)
+ }
+ },
+ }
+}).catch(err => console.error(err));
+```
+
+### 配置插件
+可以通过 npm 包的方式引入社区插件,配置如下所示:
+```typescript
+import { plugins } from '@alilc/lowcode-engine';
+import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+import PluginIssueTracker from '@alilc/lowcode-plugin-issue-tracker';
+
+// 注册一个提 issue 组件到您的编辑器中,方位默认在左栏下侧
+plugins.register(PluginIssueTracker)
+ .catch(err => console.error(err));
+```
+后续“插件扩展”章节会详细说明。
+
+### 配置设置器
+低代码引擎默认内置了设置器(详见“配置设置器”章节)。您可以通过 npm 包的方式引入自定义的设置器,配置如下所示:
+```typescript
+import { setters } from '@alilc/lowcode-engine';
+// 假设您自定义了一个 setter
+import MuxMonacoEditorSetter from './components/setters/MuxMonacoEditorSetter';
+
+// 注册设置器
+setters.registerSetter({
+ MuxMonacoEditorSetter: {
+ component: MuxMonacoEditorSetter,
+ title: 'Textarea',
+ condition: (field) => {
+ const v = field.getValue()
+ return typeof v === 'string'
+ },
+ },
+});
+```
+后续“设置器扩展”章节会详细说明。
+
+> 本章节所有可扩展配置内容在 demo 中均可找到:[https://github.com/alibaba/lowcode-demo/tree/main/demo-general](https://github.com/alibaba/lowcode-demo/tree/main/demo-general)
diff --git a/docs/docs/guide/expand/editor/theme.md b/docs/docs/guide/expand/editor/theme.md
new file mode 100644
index 0000000000..897b6b360b
--- /dev/null
+++ b/docs/docs/guide/expand/editor/theme.md
@@ -0,0 +1,157 @@
+---
+title: 主题色扩展
+sidebar_position: 9
+---
+
+## 简介
+
+主题色扩展允许用户定制多样的设计器主题,增加界面的个性化和品牌识别度。
+
+## 设计器主题色定制
+
+在 CSS 的根级别定义主题色变量可以确保这些变量在整个应用中都可用。例如:
+
+```css
+:root {
+ --color-brand: rgba(0, 108, 255, 1); /* 主品牌色 */
+ --color-brand-light: rgba(25, 122, 255, 1); /* 浅色品牌色 */
+ --color-brand-dark: rgba(0, 96, 229, 1); /* 深色品牌色 */
+}
+
+```
+
+将样式文件引入到你的设计器中,定义的 CSS 变量就可以改变设计器的主题色了。
+
+### 主题色变量
+
+以下是低代码引擎设计器支持的主题色变量列表,以及它们的用途说明:
+
+#### 品牌相关颜色
+
+- `--color-brand`: 主品牌色
+- `--color-brand-light`: 浅色品牌色
+- `--color-brand-dark`: 深色品牌色
+
+#### Icon 相关颜色
+
+- `--color-icon-normal`: 默认状态
+- `--color-icon-light`: icon light 状态
+- `--color-icon-hover`: 鼠标悬停状态
+- `--color-icon-active`: 激活状态
+- `--color-icon-reverse`: 反色状态
+- `--color-icon-disabled`: 禁用状态
+- `--color-icon-pane`: 面板颜色
+
+#### 线条和文本颜色
+
+- `--color-line-normal`: 线条颜色
+- `--color-line-darken`: 线条颜色(darken)
+- `--color-title`: 标题颜色
+- `--color-text`: 文字颜色
+- `--color-text-dark`: 文字颜色(dark)
+- `--color-text-light`: 文字颜色(light)
+- `--color-text-reverse`: 反色情况下,文字颜色
+- `--color-text-disabled`: 禁用态文字颜色
+
+#### 菜单颜色
+- `--color-context-menu-text`: 菜单项颜色
+- `--color-context-menu-text-hover`: 菜单项 hover 颜色
+- `--color-context-menu-text-disabled`: 菜单项 disabled 颜色
+
+#### 字段和边框颜色
+
+- `--color-field-label`: field 标签颜色
+- `--color-field-text`: field 文本颜色
+- `--color-field-placeholder`: field placeholder 颜色
+- `--color-field-border`: field 边框颜色
+- `--color-field-border-hover`: hover 态下,field 边框颜色
+- `--color-field-border-active`: active 态下,field 边框颜色
+- `--color-field-background`: field 背景色
+
+#### 状态颜色
+
+- `--color-success`: success 颜色
+- `--colo-success-dark`: success 颜色(dark)
+- `--color-success-light`: success 颜色(light)
+- `--color-warning`: warning 颜色
+- `--color-warning-dark`: warning 颜色(dark)
+- `--color-warning-light`: warning 颜色(light)
+- `--color-information`: information 颜色
+- `--color-information-dark`: information 颜色(dark)
+- `--color-information-light`: information 颜色(light)
+- `--color-error`: error 颜色
+- `--color-error-dark`: error 颜色(dark)
+- `--color-error-light`: error 颜色(light)
+- `--color-purple`: purple 颜色
+- `--color-brown`: brown 颜色
+
+#### 区块背景色
+
+- `--color-block-background-normal`: 区块背景色
+- `--color-block-background-light`: 区块背景色(light)。
+- `--color-block-background-shallow`: 区块背景色 shallow
+- `--color-block-background-dark`: 区块背景色(dark)
+- `--color-block-background-disabled`: 区块背景色(disabled)
+- `--color-block-background-active`: 区块背景色(active)
+- `--color-block-background-active-light`: 区块背景色(active light)
+- `--color-block-background-warning`: 区块背景色(warning)
+- `--color-block-background-error`: 区块背景色(error)
+- `--color-block-background-success`: 区块背景色(success)
+- `--color-block-background-deep-dark`: 区块背景色(deep-dark),作用于多个组件同时拖拽的背景色。
+
+#### 引擎相关颜色
+
+- `--color-canvas-detecting-background`: 画布组件 hover 时遮罩背景色。
+
+#### 其他区域背景色
+
+- `--color-layer-mask-background`: 拖拽元素时,元素原来位置的遮罩背景色
+- `--color-layer-tooltip-background`: tooltip 背景色
+- `--color-pane-background`: 面板背景色
+- `--color-background`: 设计器主要背景色
+- `--color-top-area-background`: topArea 背景色,优先级大于 `--color-pane-background`
+- `--color-left-area-background`: leftArea 背景色,优先级大于 `--color-pane-background`
+- `--color-toolbar-background`: toolbar 背景色,优先级大于 `--color-pane-background`
+- `--color-workspace-left-area-background`: 应用级 leftArea 背景色,优先级大于 `--color-pane-background`
+- `--color-workspace-top-area-background`: 应用级 topArea 背景色,优先级大于 `--color-pane-background`
+- `--color-workspace-sub-top-area-background`: 应用级二级 topArea 背景色,优先级大于 `--color-pane-background`
+
+#### 其他变量
+
+- `--workspace-sub-top-area-height`: 应用级二级 topArea 高度
+- `--top-area-height`: 顶部区域的高度
+- `--workspace-sub-top-area-margin`: 应用级二级 topArea margin
+- `--workspace-sub-top-area-padding`: 应用级二级 topArea padding
+- `--workspace-left-area-width`: 应用级 leftArea width
+- `--left-area-width`: leftArea width
+- `--simulator-top-distance`: simulator 距离容器顶部的距离
+- `--simulator-bottom-distance`: simulator 距离容器底部的距离
+- `--simulator-left-distance`: simulator 距离容器左边的距离
+- `--simulator-right-distance`: simulator 距离容器右边的距离
+- `--toolbar-padding`: toolbar 的 padding
+- `--toolbar-height`: toolbar 的高度
+- `--pane-title-height`: 面板标题高度
+- `--pane-title-font-size`: 面板标题字体大小
+- `--pane-title-padding`: 面板标题边距
+- `--context-menu-item-height`: 右键菜单项高度
+
+
+
+### 低代码引擎生态主题色定制
+
+插件、物料、设置器等生态为了支持主题色需要对样式进行改造,需要对生态中的样式升级为 css 变量。例如:
+
+```css
+/* before */
+background: #006cff;
+
+/* after */
+background: var(--color-brand, #006cff);
+
+```
+
+这里 `var(--color-brand, #默认色)` 表示使用 `--color-brand` 变量,如果该变量未定义,则使用默认颜色(#默认色)。
+
+### fusion 物料进行主题色扩展
+
+如果使用了 fusion 组件时,可以通过 [fusion 平台](https://fusion.design/) 进行主题色定制。在平台上,您可以选择不同的主题颜色,并直接应用于您的 fusion 组件,这样可以无缝地集成到您的应用设计中。
\ No newline at end of file
diff --git a/docs/docs/guide/expand/runtime/_category_.json b/docs/docs/guide/expand/runtime/_category_.json
new file mode 100644
index 0000000000..f382ad4068
--- /dev/null
+++ b/docs/docs/guide/expand/runtime/_category_.json
@@ -0,0 +1,6 @@
+{
+ "label": "扩展运行时",
+ "position": 2,
+ "collapsed": false,
+ "collapsible": true
+}
diff --git a/docs/docs/guide/expand/runtime/codeGeneration.md b/docs/docs/guide/expand/runtime/codeGeneration.md
new file mode 100644
index 0000000000..71cf81bd1c
--- /dev/null
+++ b/docs/docs/guide/expand/runtime/codeGeneration.md
@@ -0,0 +1,133 @@
+---
+title: 使用出码功能
+sidebar_position: 1
+---
+
+## 出码简述
+所谓出码,即将低代码编排出的 schema 进行解析并转换成最终可执行的代码的过程。
+## 出码的适用范围
+出码是为了更高效的运行和更灵活地定制渲染,相对而言,基于 Schema 的运行时渲染,有着能实时响应内容的变化和接入成本低的优点,但是也存在着实时解析运行的性能开销比较大和包大小比较大的问题,而且无法自由地进行扩展二次开发,功能自由度受到一定程度限制。
+当然,出码也会存在一些限制:一方面需要额外的接入成本,另一方面通常需要额外的生成代码和打包构建的时间,难以做到基于 Schema 的运行时渲染那样保存即预览的效果。
+
+所以不是所有场景都建议做出码,一般来说以下 3 个场景可以考虑使用出码进行优化。
+
+### 场景一:想要极致的打开速度,降低 LCP/FID
+这种场景比较常见的是 C 端应用,比如手淘上的页面和手机钉钉上的页面,要求能够尽快得响应用户操作,不要出现卡死的情况。当一个流入协议大小比较大的时候,前端进行解析时的开销也比较大。如果能把这部分负担转移到编译时去完成的话,前端依赖包大小就会减少许多。从而也提升了加载速度,降低了带宽消耗。页面越简单,这其中的 gap 就会越明显。
+
+### 场景二:老项目 + 新需求,想用搭建产出
+这是一个很常见的场景,毕竟迁移或者重构都是有一个过程的,阿里的业务都是一边跑一边换发动机。在这种场景中,我们不可能要求使用运行时方案来做实现,因为运行时是一个项目级别的能力,最好是项目中统一使用他这一种方式,保证体验的一致性与连贯性。所以我们可以只在低代码平台上搭建新的业务页面,然后通过出码模块导出这些页面的源码,连同一些全局依赖模块,一起 Merge 到老项目中。完成开发体验的优化。
+
+### 场景三:协议不能描述部分代码逻辑(协议功能不足或特别定制化的逻辑)
+当我们发现一些逻辑诉求不能在目前协议中很好地表达的时候,这其实是项目复杂度较高的一个信号。比较好的方式就是将低代码研发和源码研发结合起来。这种模式下最大的诉求点之一就是,需要将搭建的内容输出为可读性和确定性都比较良好的代码模块。这也就是出码模块需要支持好的使用场景了。
+
+## 如何使用
+### 1) 通过命令行快速体验
+
+欢迎使用命令行工具快速体验:`npx @alilc/lowcode-code-generator -i example-schema.json -o generated -s icejs3`
+
+--其中 example-schema.json 可以从[这里下载](https://alifd.alicdn.com/npm/@alilc/lowcode-code-generator@latest/example-schema.json)
+
+### 2) 通过设计器插件快速体验
+
+1. 安装依赖: `npm install --save @alilc/lowcode-plugin-code-generator`
+2. 注册插件:
+
+```typescript
+import { plugins } from '@alilc/lowcode-engine';
+import CodeGenPlugin from '@alilc/lowcode-plugin-code-generator';
+
+// 在你的初始化函数中:
+await plugins.register(CodeGenPlugin);
+
+// 如果您不希望自动加上出码按钮,则可以这样注册
+await plugins.register(CodeGenPlugin, { disableCodeGenActionBtn: true });
+```
+
+然后运行你的低代码编辑器项目即可 -- 在设计器的右上角会出现一个“出码”按钮,点击即可在浏览器中出码并预览。
+
+### 3)服务端出码接入
+
+此代码生成器一开始就是为服务端出码设计的,你可以直接这样来在 node.js 环境中使用:
+
+1. 安装依赖: `npm install --save @alilc/lowcode-code-generator`
+2. 引入代码生成器:
+
+```javascript
+import CodeGenerator from '@alilc/lowcode-code-generator';
+```
+
+3. 创建项目构建器:
+
+```javascript
+const projectBuilder = CodeGenerator.solutions.icejs();
+```
+
+4. 生成代码
+
+```javascript
+const project = await projectBuilder.generateProject(
+ schema, // 编排搭建出来的 schema
+);
+```
+
+5. 将生成的代码写入到磁盘中 (也可以生成一个 zip 包)
+
+```javascript
+// 写入磁盘
+await CodeGenerator.publishers.disk().publish({
+ project, // 上一步生成的 project
+ outputPath: '/path/to/your/output/dir', // 输出目录
+ projectSlug: 'your-project-slug', // 项目标识
+});
+
+// 写入到 zip 包
+await CodeGenerator.publishers.zip().publish({
+ project, // 上一步生成的 project
+ outputPath: '/path/to/your/output/dir', // 输出目录
+ projectSlug: 'your-project-slug', // 项目标识 -- 对应生成 your-project-slug.zip 文件
+});
+```
+
+注:一般来说在服务端出码可以跟 github/gitlab, CI 和 CD 流程等一起串起来使用,通常用于优化性能。
+
+### 4)浏览器中出码接入
+
+随着现在电脑性能和浏览器技术的发展,出码其实已经不必非得在服务端做了,借助于 Web Worker 特性,可以在浏览器中进行出码:
+
+1. 安装依赖: `npm install --save @alilc/lowcode-code-generator`
+2. 引入代码生成器:
+
+```javascript
+import * as CodeGenerator from '@alilc/lowcode-code-generator/standalone-loader';
+```
+
+3. 【可选】提前初始化代码生成器:
+
+```javascript
+// 提前初始化下,这样后面用的时候更快 (这个 init 内部会提前准备好创建 worker 的一些资源)
+await CodeGenerator.init();
+```
+
+4. 出码
+
+```javascript
+const result = await CodeGenerator.generateCode({
+ solution: 'icejs', // 出码方案 (目前内置有 icejs、icejs3 和 rax )
+ schema, // 编排搭建出来的 schema
+});
+
+console.log(result); // 出码结果 (默认是递归结构描述的,可以传 flattenResult: true 以生成扁平结构的结果)
+```
+
+注:一般来说在浏览器中出码适合做即时预览功能。
+
+### 5)自定义出码
+前端框架灵活多变,默认内置的出码方案很难满足所有人的需求,好在此代码生成器支持非常灵活的插件机制 -- 内置功能大多都是通过插件完成的(在 `src/plugins`下),比如:
+
+
+所以您可以通过添加自己的插件或替换掉默认内置的插件来实现您的自定义功能。
+为了方便自定义出码方案,出码模块还提供自定义出码方案的脚手架功能,即执行下面脚本即可生成一个自定义出码方案:
+```shell
+npx @alilc/lowcode-code-generator init-solution
+```
+里面内置了一个示例的插件 (在 `src/plugins/example.ts`中),您可以根据注释引导来完善相关插件,从而组合生成您的专属出码方案 (`src/index.ts`)。您所生成的出码方案可以发布成 NPM 包,从而能按上文 1~4 中的使用方案进行使用。
diff --git a/docs/docs/guide/expand/runtime/renderer.md b/docs/docs/guide/expand/runtime/renderer.md
new file mode 100644
index 0000000000..4e6d914bbf
--- /dev/null
+++ b/docs/docs/guide/expand/runtime/renderer.md
@@ -0,0 +1,348 @@
+---
+title: 使用渲染模块
+sidebar_position: 0
+---
+## 快速使用
+渲染依赖于 schema 和 components。其中 schema 和 components 需要一一对应,schema 中使用到的组件都需要在 components 中进行声明,否则无法正常渲染。
+### 简单示例
+
+```jsx
+import ReactRenderer from '@alilc/lowcode-react-renderer';
+import ReactDOM from 'react-dom';
+import { Button } from '@alifd/next';
+
+const schema = {
+ componentName: 'Page',
+ props: {},
+ children: [
+ {
+ componentName: 'Button',
+ props: {
+ type: 'primary',
+ style: {
+ color: '#2077ff'
+ },
+ },
+ children: '确定',
+ },
+ ],
+};
+
+const components = {
+ Button,
+};
+
+ReactDOM.render((
+
+), document.getElementById('root'));
+```
+
+####
+### 项目使用示例
+> [设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html)
+> 项目代码完整示例:[https://github.com/alibaba/lowcode-demo](https://github.com/alibaba/lowcode-demo)
+
+**step 1:在设计器中获取组件列表**
+```typescript
+import { material, project } from '@alilc/lowcode-engine';
+const packages = material.getAssets().packages
+```
+**step 2:在设计器中获取当前配置页面的 schema**
+```typescript
+import { material, project } from '@alilc/lowcode-engine';
+
+const schema = project.exportSchema();
+```
+
+
+**step 3:以某种方式存储 schema 和 packages**
+这里用 localStorage 作为存储示例,真实项目中使用数据库或者其他存储方式。
+```typescript
+window.localStorage.setItem(
+ 'projectSchema',
+ JSON.stringify(project.exportSchema())
+);
+const packages = await filterPackages(material.getAssets().packages);
+window.localStorage.setItem(
+ 'packages',
+ JSON.stringify(packages)
+);
+```
+**step 4:预览时,获取存储的 schema 和 packages**
+```typescript
+const packages = JSON.parse(window.localStorage.getItem('packages') || '');
+const projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || '');
+const { componentsMap: componentsMapArray, componentsTree } = projectSchema;
+```
+**step 5:通过整合 schema 和 packages 信息,进行渲染**
+```typescript
+import ReactDOM from 'react-dom';
+import React, { useState } from 'react';
+import { Loading } from '@alifd/next';
+import { buildComponents, assetBundle, AssetLevel, AssetLoader } from '@alilc/lowcode-utils';
+import ReactRenderer from '@alilc/lowcode-react-renderer';
+import { injectComponents } from '@alilc/lowcode-plugin-inject';
+
+const SamplePreview = () => {
+ const [data, setData] = useState({});
+
+ async function init() {
+ // 渲染前置处理,初始化项目 schema 和资产包为渲染模块所需的 schema prop 和 components prop
+ const packages = JSON.parse(window.localStorage.getItem('packages') || '');
+ const projectSchema = JSON.parse(window.localStorage.getItem('projectSchema') || '');
+ const { componentsMap: componentsMapArray, componentsTree } = projectSchema;
+ const componentsMap: any = {};
+ componentsMapArray.forEach((component: any) => {
+ componentsMap[component.componentName] = component;
+ });
+ const schema = componentsTree[0];
+
+ const libraryMap = {};
+ const libraryAsset = [];
+ packages.forEach(({ package: _package, library, urls, renderUrls }) => {
+ libraryMap[_package] = library;
+ if (renderUrls) {
+ libraryAsset.push(renderUrls);
+ } else if (urls) {
+ libraryAsset.push(urls);
+ }
+ });
+
+ const vendors = [assetBundle(libraryAsset, AssetLevel.Library)];
+
+ const assetLoader = new AssetLoader();
+ await assetLoader.load(libraryAsset);
+ const components = await injectComponents(buildComponents(libraryMap, componentsMap));
+
+ setData({
+ schema,
+ components,
+ });
+ }
+
+ const { schema, components } = data;
+
+ if (!schema || !components) {
+ init();
+ return ;
+ }
+
+ return (
+
+
+
+ );
+};
+
+ReactDOM.render(, document.getElementById('ice-container'));
+
+```
+### 国际化示例
+```typescript
+class Demo extends PureComponent {
+ static displayName = 'renderer-demo';
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+```
+
+## API
+
+| 参数 | 说明 | 类型 | 必选 |
+| --- | --- | --- | --- |
+| schema | 符合[搭建协议](https://lowcode-engine.cn/lowcode)的数据 | Object | 是 |
+| components | 组件依赖的实例 | Object | 是 |
+| componentsMap | 组件的配置信息 | Object | 否 |
+| appHelper | 渲染模块全局上下文 | Object | 否 |
+| designMode | 设计模式,可选值:extend、border、preview | String | 否 |
+| suspended | 是否挂起 | Boolean | 否 |
+| onCompGetRef | 组件 ref 回调(schema, ref)=> {} | Function | 否 |
+| onCompGetCtx | 组件 ctx 更新回调 (schema, ctx) => {} | Function | 否 |
+| rendererName | 渲染类型,标识当前模块是以什么类型进行渲染的 | string | 否 |
+| customCreateElement | 自定义创建 element 的钩子
+(Component, props, children) => {} | Function | 否 |
+| notFoundComponent | 当组件找不到时,可以通过这个参数自定义展示文案。 | Component | 否 |
+| thisRequiredInJSE | 为 true 的情况下 JSExpression 仅支持通过 this 来访问。假如需要兼容原来的 'state.xxx',则设置为 false,推荐使用 true。 | Boolean | 否 |
+| locale | 国际化语言类型 | string | 否 |
+| messages | 国际化语言对象 | Object | 否 |
+
+
+### schema
+
+搭建基础协议数据,渲染模块将基于 schema 中的内容进行实时渲染。
+
+### messages
+国际化内容,需要配合 locale 使用
+messages 格式示例:
+```typescript
+{
+ 'zh-CN': {
+ 'hello-world': '你好,世界!',
+ },
+ 'en-US': {
+ 'hello-world': 'Hello world!',
+ },
+}
+```
+
+### locale
+当前语言类型
+示例:'zh-CN' | 'en-US'
+
+### components
+
+渲染模块渲染页面需要用到的组件依赖的实例,`components` 对象中的 Key 需要和搭建 schema 中的`componentName` 字段对应。
+
+### componentsMap
+
+> 在生产环境下不需要设置。
+
+
+配置规范参见[《低代码引擎搭建协议规范》](https://lowcode-engine.cn/lowcode),主要在搭建场景中使用,用于提升用户搭建体验。
+
+- 属性配置校验:用户可以配置组件特定属性的 `propTypes`,在搭建场景中用户输入的属性值不满足 `propType` 配置时,渲染模块会将当前属性设置为 `undefined`,避免组件抛错导致编辑器崩溃;
+- `isContainer` 标记:当组件被设置为容器组件且当前容器组件内没有其他组件时,用户可以通过拖拽方式将组件直接添加到容器组件内部;
+- `parentRule` 校验:当用户使用的组件未出现在组件配置的 `parentRule` 组件内部时,渲染模块会使用 `visualDom` 组件进行占位,避免组件抛错的同时在下钻编辑场景也能够不阻塞用户配置,典型的场景如`Step.Item`、`Table.Column`、`Tab.Item` 等等。
+
+### appHelper
+
+appHelper 主要用于设置渲染模块的全局上下文,目前 appHelper 支持设置以下上下文:
+
+- `utils`:全局公共函数
+- `constants`:全局常量
+- `location`:react-router 的 `location` 实例
+- `history`:react-router 的 `history` 实例
+
+设置了 appHelper 以后,上下文会直接挂载到容器组件的 this 上,用户可以在搭建协议中的 function 及变量表达式场景使用上下文,具体使用方式如下所示:
+**schema:**
+
+```javascript
+export default {
+ "componentName": "Page",
+ "fileName": "test",
+ "props": {},
+ "children": [{
+ "componentName": "Div",
+ "props": {},
+ "children": [{
+ "componentName": "Text",
+ "props": {
+ "text": {
+ "type": "JSExpression",
+ "value": "this.location.pathname"
+ }
+ }
+ }, {
+ "componentName": "Button",
+ "props": {
+ "type": "primary",
+ "style": {
+ "marginLeft": 10
+ },
+ "onClick": {
+ "type": "JSExpression",
+ "value": "function onClick(e) { this.utils.xxx(this.constants.yyy);}"
+ }
+ },
+ "children": "click me"
+ }]
+ }]
+}
+```
+
+```typescript
+import ReactRenderer from '@alilc/lowcode-react-renderer';
+import ReactDOM from 'react-dom';
+import { Button } from '@alifd/next';
+import schema from './schema'
+
+const components = {
+ Button,
+};
+
+ReactDOM.render((
+ {}
+ }
+ }}
+ />
+), document.getElementById('root'));
+```
+### designMode
+
+> 在生产环境下不需要设置。
+
+
+designMode 属性主要在搭建场景中使用,主要有以下作用:
+
+- 当 `designMode` 改变时,触发当前 schema 中所有组件重新渲染
+- 当 `designMode` 设置为 `design` 时,渲染模块会为 `Dialog`、`Overlay` 等初始状态无 dom 渲染的组件外层包裹一层 div,使其在画布中能够展示边框供用户选中
+
+### suspended
+
+渲染模块是否挂起,当设置为 `true` 时,渲染模块最外层容器的 `shouldComponentUpdate`将始终返回 false,在下钻编辑或者多引擎渲染的场景会用到该参数。
+
+### onCompGetRef
+
+组件 ref 的回调,在搭建场景下编排模块可以根据该回调获取组件实例并实现生命周期注入或者组件 DOM 操作等功能,回调函数主要包含两个参数:
+
+- `schema`:当前组件的 schema 模型结构
+- `ref`:当前组件的 ref 实例
+
+### onCompGetCtx
+组件 ctx 更新的回调,在组件每次 render 渲染周期我们都会为组件构造新的上下文环境,因此该回调函数会在组件每次 render 过程中触发,主要包含两个参数:
+
+- `schema`:当前组件的 schema 模型结构
+- `ctx`:当前组件的上下文信息,主要包含以下内容:
+ - `page`:当前页面容器实例
+ - `this`: 当前组件所属的容器组件实例
+ - `item`/`index`: 循环上下文(属性 key 可以根据 loopArgs 进行定制)
+ - `form`: 表单上下文
+
+### rendererName
+渲染类型,标识当前模块是以什么类型进行渲染的
+
+- `LowCodeRenderer`: 低代码组件
+- `PageRenderer`: 页面
+
+### customCreateElement
+自定义创建 element 的钩子,用于在渲染前后对组件进行一些处理,包括但不限于增加 props、删除部分 props。主要包含三个参数:
+
+- `Component`:要渲染的组件
+- `props`:要渲染的组件的 props
+- `children`:要渲染的组件的子元素
+
+### thisRequiredInJSE
+> 版本 >= 1.0.11
+
+默认值:true
+为 true 的情况下 JSExpression 仅支持通过 this 来访问。假如需要兼容原来的 'state.xxx',则设置为 false,推荐使用 true。
diff --git a/docs/docs/guide/quickStart/_category_.json b/docs/docs/guide/quickStart/_category_.json
new file mode 100644
index 0000000000..0a47c9da50
--- /dev/null
+++ b/docs/docs/guide/quickStart/_category_.json
@@ -0,0 +1,6 @@
+{
+ "label": "入门",
+ "position": 0,
+ "collapsed": false,
+ "collapsible": true
+}
diff --git a/docs/docs/guide/quickStart/demo.md b/docs/docs/guide/quickStart/demo.md
new file mode 100644
index 0000000000..ee76d5aa1b
--- /dev/null
+++ b/docs/docs/guide/quickStart/demo.md
@@ -0,0 +1,56 @@
+---
+title: 试用低代码引擎 Demo
+sidebar_position: 2
+---
+## 访问地址
+
+低代码引擎的 Demo 可以通过如下永久链接访问到:
+
+[设计器 demo](https://lowcode-engine.cn/demo/demo-general/index.html)
+
+> 注意我们会经常更新 demo,所以您可以通过上述链接得到最新版地址。
+
+
+## 低代码引擎 Demo 功能概览
+
+我们可以从 Demo 的项目中看到页面中有很多的区块:
+
+
+
+它主要包含这些功能点:
+
+
+
+### 顶部:操作区
+
+- 右侧:撤回和重做、保存到本地、重置页面、预览、异步加载资源
+### 左侧:面板与操作区
+- 大纲面板:可以调整页面内的组件树结构
+- 物料面板:可以查找组件,并在此拖动组件到编辑器画布中
+- 源码面板:可以编辑页面级别的 JavaScript 代码和 CSS 配置
+- 提交 Issue:可以给引擎开发提 bug
+- Schema 编辑:可以编辑页面的底层数据
+- 中英文切换:可以切换编辑器的语言
+
+### 中部:可视化页面编辑画布区域
+- 点击组件在右侧面板中能够显示出对应组件的属性配置选项
+- 拖拽修改组件的排列顺序
+- 将组件拖拽到容器类型的组件中
+- 复制组件:点击组件右上角的复制按钮
+- 删除组件:点击组件右上角的 X 或者直接使用 `Delete` 键
+
+### 右侧:组件级别配置
+- 选中的组件:从页面开始一直到当前选中的组件位置,点击对应的名称可以切换到对应的组件上
+- 选中组件的配置:当前组件的大类目选项,根据组件类型不同,包含如下子类目:
+ - 属性:组件的基础属性值设置
+ - 样式:组件的样式配置
+ - 事件:绑定组件对外暴露的事件
+ - 高级:循环、条件渲染与 key 设置
+
+## 深入使用低代码引擎 Demo
+
+我们在低代码引擎 Demo 中直接内置了产品使用文档,对常见场景中的使用进行了向导,它的入口如下:
+
+
+
+如果暂时没有看到对应的产品使用文档,可以通过此永久链接直接访问:[https://lowcode-engine.cn/site/docs/demoUsage/intro](https://lowcode-engine.cn/site/docs/demoUsage/intro)
diff --git a/docs/docs/guide/quickStart/intro.md b/docs/docs/guide/quickStart/intro.md
new file mode 100644
index 0000000000..b65baac269
--- /dev/null
+++ b/docs/docs/guide/quickStart/intro.md
@@ -0,0 +1,63 @@
+---
+title: 简介
+sidebar_position: 1
+---
+
+# 阿里低代码引擎简介
+
+## 低代码介绍
+
+零代码、低代码的概念在整个全球行业内已经流行了很长一段时间。通常意义上的低代码定义会有三个关键点:
+
+1. 一个用于生产软件的可视化编辑器
+2. 中间包含了一些用于组装的物料,可以通过编排、组合和配置它们以生成丰富的功能或表现
+3. 最后的实施结果是成本降低
+
+通常情况下低代码平台会具备以下的几个能力:
+
+- **可视化页面搭建**,通过简单的拖拽完成应用页面开发,对前端技能没有要求或不需要特别专业的了解;
+- **可视化模型设计**,与业务相关的数据存储变得更容易理解,甚至大多数简单场景可以做到表单即模型,模型字段的类型更加业务化;
+- **可视化流程设计**,不管是业务流程还是审批流程,都可以通过简单的点线连接来进行配置;
+- **可视化报表及数据分析**,BI 数据分析能力成为标配,随时随地通过拖拽选择来定义自定义分析报表;
+- **可视化服务与数据开放、集成**,具备与其他系统互联互通的配置;
+- **权限、角色设置标准化和业务化**,通过策略规则配置来将数据、操作的权限进行精细化管理;
+- **无需关心服务器、数据库等底层运维、计算设施设备、网络等等复杂技术概念**,具备安全、性能的统一解决方案,开发者只需要专注于业务本身;
+
+有了上面这些,你会发现即使是个技术小白,只要你了解业务,就能不受束缚的完成大多数业务应用的搭建。但低代码本身也不仅仅是为技术小白准备的。在实践中,低代码因为通过组件化、模块化的思路让业务的抽象更加容易,而且在扩展及配置化上带来了更加新鲜的模式探索,技术人员的架构设计成本和实施成本也就降了很多。
+
+市面上常见的低代码产品[可以看 Golden 的梳理](https://golden.com/wiki/No-code_%2F_low-code_development-NMGMEA6)。
+
+## 低代码引擎介绍
+
+**低代码引擎是一款为低代码平台开发者提供的,具备强大定制扩展能力的低代码设计器研发框架。**
+
+下面简单描述定义中的子部分:
+
+**低代码设计器**
+现如今低代码平台越来越多,而每一个低代码平台中都会有的一个能力就是搭建和配置页面、模块的页面,这个页面我们称为设计器。例如,下图是中后台低代码平台的设计器。
+
+设计器承载着低代码平台的核心功能,包括入料、编排、组件配置、画布渲染等等。由于其功能多,打磨精细难,也是低代码平台建设最耗时的地方。
+
+**定制扩展能力**
+
+什么是扩展能力呢,一方面我们可以快速拥有一份标准的低代码设计器,另外一方面如果有业务独特的功能需要,我们可以不用看它的源码、不用关心其实现,可以使用 API、插件等方式快速完成能力的开发。
+而低代码引擎对于设计器的扩展能力支持基本上覆盖了低代码设计器的所有功能点。下图是针对标准的设计器提供了扩展功能的区域。
+
+**低代码设计器研发框架**
+
+低代码引擎的核心是设计器,通过扩展、周边生态等可以产出各式各样的设计器。它不是一套可以适合所有人的低代码平台,而是帮助低代码平台的开发者,快速生产低代码平台的工具。
+
+## 寻找适合您的低代码解决方案
+
+帮助用户根据个人或企业需求选择合适的低代码产品。
+
+| 特性/产品 | 低代码引擎 | Lab平台 | UIPaaS |
+|-----------------|-----------------------------------------|-----------------------------------------|--------------------------------------------|
+| **适用用户** | 前端开发者 | 需要快速搭建应用/页面的用户 | 企业用户,需要大规模部署低代码解决方案的组织 |
+| **产品特点** | 设计器研发框架,适合定制开发 | 低代码平台, 可视化操作界面,易于上手 | 低代码平台孵化器,企业级功能 |
+| **使用场景** | 定制和开发低代码平台的设计器部分 | 通过可视化, 快速开发应用或页面 | 帮助具有一定规模软件研发团队的的企业低成本定制低代码平台 |
+| **产品关系** | 开源产品 | 基于UIPaaS技术实现, 展示了UIPaaS的部分能力 | 提供完整的低代码平台解决方案,商业产品 |
+| **收费情况** | 免费 | 可免费使用(有额度限制),不提供私有化部署售卖 | 仅提供私有化部署售卖 |
+| **官方网站** | [低代码引擎官网](https://lowcode-engine.cn/) | [Lab平台官网](https://lab.lowcode-engine.cn/) | [UIPaaS官网](https://uipaas.net/) |
+
+*注:请根据您的具体需求和条件选择合适的产品。如需更详细的信息,请访问各产品的官方网站。*
diff --git a/docs/docs/guide/quickStart/start.md b/docs/docs/guide/quickStart/start.md
new file mode 100644
index 0000000000..356f501769
--- /dev/null
+++ b/docs/docs/guide/quickStart/start.md
@@ -0,0 +1,411 @@
+---
+sidebar_position: 3
+title: 快速开始
+---
+
+## 前置知识
+
+我们假定你已经对 HTML 和 JavaScript 都比较熟悉了。即便你之前使用其他编程语言,你也可以跟上这篇教程的。除此之外,我们假定你也已经熟悉了一些编程的概念,例如,函数、对象、数组,以及 class 的一些内容。
+
+如果你想回顾一下 JavaScript,你可以阅读[这篇教程](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript)。注意,我们也用到了一些 ES6(较新的 JavaScript 版本)的特性。在这篇教程里,我们主要使用了[箭头函数(arrow functions)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions)、[class](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes)、[let](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let) 语句和 [const](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/const) 语句。你可以使用 [Babel REPL](https://babeljs.io/repl/#?presets=react&code_lz=MYewdgzgLgBApgGzgWzmWBeGAeAFgRgD4AJRBEAGhgHcQAnBAEwEJsB6AwgbgChRJY_KAEMAlmDh0YWRiGABXVOgB0AczhQAokiVQAQgE8AkowAUAcjogQUcwEpeAJTjDgUACIB5ALLK6aRklTRBQ0KCohMQk6Bx4gA) 在线预览 ES6 的编译结果。
+
+## 环境准备
+
+### WSL(Windows 电脑)
+
+Window 环境需要使用 WSL 在 windows 下进行低代码引擎相关的开发。安装教程 ➡️ [WSL 安装教程](https://docs.microsoft.com/zh-cn/windows/wsl/install)。
**对于 Window 环境来说,之后所有需要执行命令的操作都是在 WSL 终端执行的。**
+
+### Node
+
+node 版本推荐 16.18.0。
+
+#### 查看 Node 版本
+
+
+
+#### 通过 n 来管理 node 版本
+
+可以安装 [n](https://www.npmjs.com/package/n) 来管理和变更 node 版本。
+
+##### 安装 n
+
+```bash
+npm install -g n
+```
+
+##### 变更 node 版本
+
+```bash
+n 14.17.0
+```
+
+### React
+
+低代码引擎的扩展能力都是基于 React 来研发的,在继续阅读之前最好有一定的 React 基础,React 学习教程 ➡️ [React 快速开始教程](https://zh-hans.reactjs.org/docs/getting-started.html)。
+
+### 下载 Demo
+
+可以前往 github()将 DEMO 下载到本地。
+
+#### git clone
+
+##### HTTPS
+
+需要使用到 git 工具
+
+```bash
+git clone https://github.com/alibaba/lowcode-demo.git
+```
+
+##### SSH
+
+需要配置 SSH key,如果没有配置可以
+
+```bash
+git clone git@github.com:alibaba/lowcode-demo.git
+```
+
+#### 下载 Zip 包
+
+
+
+### 选择一个 demo 项目
+
+在 以 `demo-general` 为例:
+
+```bash
+cd demo-general
+```
+
+### 安装依赖
+
+在 `lowcode-demo/demo-general` 目录下执行:
+
+```bash
+npm install
+```
+
+### 启动 demo
+
+在 `lowcode-demo/demo-general` 目录下执行:
+
+```bash
+npm run start
+```
+
+之后就可以通过 [http://localhost:5556/](http://localhost:5556/) 来访问我们的 DEMO 了。
+
+## 认识 Demo
+
+我们的 Demo 是一个**低代码平台的设计器**。它是一个低代码平台中最重要的一环,用户可以在这里通过拖拽、配置、写代码等等来完成一个页面的开发。由于用户的人群不同、场景不同、诉求不同等等,这个页面的功能就会有所差异。
+
+这里记住**设计器**这个词,它描述的就是下面的这个页面,后面我们会经常看到它。
+
+
+### 场景介绍
+
+
+
+Demo 根据**不同的设计器所需要的物料不同**,分为了下面的 8 个场景:
+
+- 综合场景
+- 基础 fusion 组件
+- 基础 fusion 组件 + 单自定义组件
+- 基础 antd 组件
+- 自定义初始化引擎
+- 扩展节点操作项
+- 基于 next 实现的高级表单低代码物料
+- antd 高级组件 + formily 表单组件
+
+可以点开不同的场景,看看他们使用的物料。
+
+
+### 目录介绍
+
+仓库下每个 demo-xxx-xxx 目录都是一个可独立运行的 demo 工程,分别对应到刚刚介绍的场景。
+
+
+
+不同场景的目录结构实际上都是类似的,这里我们主要介绍一下综合场景的目录结构即可。
+
+
+
+介绍下其中主要的内容
+
+- 设计器入口文件 `src/index.ts` 这个文件做了下述几个事情:
+ - 通过 plugins.register 注册各种插件,包括官方插件 (已发布 npm 包形式的插件) 和 `plugins` 目录下内置的示例插件
+ - 通过 init 初始化低代码设计器
+- plugins 目录,存放的都是示例插件,方便用户从中看到一个插件是如何实现的
+- services 目录,模拟数据请求、提供默认 schema、默认资产包等,此目录下内容在真实项目中应替换成真实的与服务端交互的服务。
+- 预览页面入口文件 `preview.tsx`
+
+剩下的各位看官可以通过源码来进一步了解。
+
+做了这些事情之后,我们的低代码设计器就已经有了基本的能力了。也就是最开始我们看到的这样。
+
+
+
+接下来我们就根据我们自己的诉求通过对设计器进行扩展,改动成我们需要的设计器功能。
+
+## 开发一个插件
+
+### 方式 1:在 DEMO 中直接新增插件
+
+
+
+可以在 demo/sample-plugins 直接新增插件,这里我新增的插件目录是 plugin-demo。并且新增了 index.tsx 文件,将下面的代码粘贴到 index.tsx 中。
+
+```javascript
+import * as React from 'react';
+import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+
+const LowcodePluginPluginDemo = (ctx: IPublicModelPluginContext) => {
+ return {
+ // 插件对外暴露的数据和方法
+ exports() {
+ return {
+ data: '你可以把插件的数据这样对外暴露',
+ func: () => {
+ console.log('方法也是一样');
+ },
+ };
+ },
+ // 插件的初始化函数,在引擎初始化之后会立刻调用
+ init() {
+ // 你可以拿到其他插件暴露的方法和属性
+ // const { data, func } = ctx.plugins.pluginA;
+ // func();
+
+ // console.log(options.name);
+
+ // 往引擎增加面板
+ ctx.skeleton.add({
+ area: 'leftArea',
+ name: 'LowcodePluginPluginDemoPane',
+ type: 'PanelDock',
+ props: {
+ description: 'Demo',
+ },
+ content: 这是一个 Demo 面板
,
+ });
+
+ ctx.logger.log('打个日志');
+ },
+ };
+};
+
+// 插件名,注册环境下唯一
+LowcodePluginPluginDemo.pluginName = 'LowcodePluginPluginDemo';
+LowcodePluginPluginDemo.meta = {
+ // 依赖的插件(插件名数组)
+ dependencies: [],
+ engines: {
+ lowcodeEngine: '^1.0.0', // 插件需要配合 ^1.0.0 的引擎才可运行
+ },
+};
+
+export default LowcodePluginPluginDemo;
+```
+
+在 src/index.ts 中新增下面代码
+
+
+
+这样在我们的设计器中就新增了一个 Demo 面板。
+
+
+
+### 方式 2:在新的仓库下开发插件
+
+初始化
+
+```bash
+npm init @alilc/element your-plugin-name
+```
+
+选择设计器插件(plugin)
+
+
+
+根据操作完善信息
+
+
+
+插件项目就初始化完成了
+
+
+
+在插件项目下安装依赖
+
+```bash
+npm install
+```
+
+启动项目
+
+```bash
+npm run start
+```
+
+调试项目
+
+
+
+在 Demo 中调试项目
+
+在 build.json 下面新增 "inject": true,就可以在 [https://lowcode-engine.cn/demo/demo-general/index.html?debug](https://lowcode-engine.cn/demo/demo-general/index.html?debug) 页面下进行调试了。
+
+
+
+## 开发一个自定义物料
+
+### 初始化物料
+
+```bash
+npm init @alilc/element your-material-demo
+```
+
+选择组件/物料栏
+
+
+
+配置其他信息
+
+
+
+这样我们就初始化好了一个 React 物料。
+
+
+
+### 启动并调试物料
+
+#### 安装依赖
+
+```bash
+npm i
+```
+
+#### 启动
+
+```bash
+npm run lowcode:dev
+```
+
+我们就可以通过 [http://localhost:3333/](http://localhost:3333/) 看到我们的研发的物料了。
+
+
+
+#### 在 Demo 中调试
+
+```bash
+npm i @alilc/build-plugin-alt
+```
+
+修改 build.lowcode.js
+
+
+
+如图,新增如下代码
+
+```javascript
+[
+ '@alilc/build-plugin-alt',
+ {
+ type: 'component',
+ inject: true,
+ library,
+ // 配置要打开的页面,在注入调试模式下,不配置此项的话不会打开浏览器
+ // 支持直接使用官方 demo 项目:https://lowcode-engine.cn/demo/index.html
+ openUrl: 'https://lowcode-engine.cn/demo/index.html?debug',
+ },
+],
+```
+
+我们重新启动项目,就可以在 Demo 中找到我们的自定义组件。
+
+
+
+### 发布
+
+首先进行构建
+
+```bash
+npm run lowcode:build
+```
+
+发布组件
+
+```bash
+npm publish
+```
+
+这里我发布的组件是 [my-material-demo](https://www.npmjs.com/package/my-material-demo)。在发布之后我们就会有两个重要的文件:
+
+- 低代码描述:[https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js](https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js)
+- 组件代码:[https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js](https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js)
+
+我们也可以从 [https://unpkg.com/my-material-demo@0.1.0/build/lowcode/assets-prod.json](https://unpkg.com/my-material-demo@0.1.0/build/lowcode/assets-prod.json) 找到我们的资产包描述。
+
+```bash
+{
+ "packages": [
+ {
+ "package": "my-material-demo",
+ "version": "0.1.0",
+ "library": "BizComp",
+ "urls": [
+ "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js",
+ "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.css"
+ ],
+ "editUrls": [
+ "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/view.js",
+ "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/view.css"
+ ],
+ "advancedUrls": {
+ "default": [
+ "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.js",
+ "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/render/default/view.css"
+ ]
+ },
+ "advancedEditUrls": {}
+ }
+ ],
+ "components": [
+ {
+ "exportName": "MyMaterialDemoMeta",
+ "npm": {
+ "package": "my-material-demo",
+ "version": "0.1.0"
+ },
+ "url": "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js",
+ "urls": {
+ "default": "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js"
+ },
+ "advancedUrls": {
+ "default": [
+ "https://unpkg.com/my-material-demo@0.1.0/build/lowcode/meta.js"
+ ]
+ }
+ }
+ ],
+}
+```
+
+### 使用
+
+我们将刚刚发布的组件的 assets-prod.json 的内容放到 demo 的 src/universal/assets.json 中。
+
+> 最好放到最后,防止因为资源加载顺序问题导致出现报错。
+
+如图,新增 packages 配置
+
+
+如图,新增 components 配置
+
+
+
+这时候再启动 DEMO 项目,就会有新的低代码物料了。接下来就按照你们的需求,继续扩展物料吧。
+
+## 总结
+
+这里只是简单的介绍了一些低代码引擎的基础能力,带大家简单的对低代码 DEMO 进行扩展,定制一些新的功能。低代码引擎的能力还有很多很多,可以继续去探索更多的功能。
diff --git a/docs/code-specification.md b/docs/docs/participate/code-specification.md
similarity index 90%
rename from docs/code-specification.md
rename to docs/docs/participate/code-specification.md
index 0a7c9f5556..d6b387e305 100644
--- a/docs/code-specification.md
+++ b/docs/docs/participate/code-specification.md
@@ -1,3 +1,8 @@
+---
+title: 编码规约
+sidebar_position: 5
+---
+
编码规约
---
@@ -22,7 +27,7 @@
- 不要在全局命名空间内定义类型/值
- 共享的类型应该在 `types.ts` 里定义
- 在一个文件里,类型定义应该出现在顶部
- - interface 和 type 很类似,原则上能用 interface 实现,就用 interface , 如果不能才用 type
+ - interface 和 type 很类似,原则上能用 interface 实现,就用 interface , 如果不能才用 type
### 注释
diff --git a/docs/docs/participate/flow.md b/docs/docs/participate/flow.md
new file mode 100644
index 0000000000..b8b804e123
--- /dev/null
+++ b/docs/docs/participate/flow.md
@@ -0,0 +1,187 @@
+---
+title: 研发协作流程
+sidebar_position: 2
+---
+## 代码风格
+引擎项目配置了 eslint 和 stylelint,在每次 git commit 前都会检查代码风格,假如有报错,请修改后再提交。(**严禁 -n 提交,-n 也逃脱不了 github workflow 的 lint 检查,放弃吧,骚年~**)
+
+## 测试机制
+每次提交代码前,务必本地跑一次单元测试,通过后再提交 MR。
+
+假如涉及新的功能,需要**补充相应的单元测试**,目前引擎核心模块的单测覆盖率都在 80%+,假如降低了覆盖率,将会不予以通过。
+
+跑单测流程:
+
+1. 项目根目录下执行 npm run build
+2. 只改了一个包,比如 designer,则在 designer 目录下,执行 npm test
+3. (or)改了多个包,则在根目录下执行 npm test
+## commit 风格
+几点要求:
+
+1. commit message 格式遵循 [ConvensionalCommits](https://www.conventionalcommits.org/en/v1.0.0/#summary)
+
+
+2. 请按照一个 bugfix / feature 对应一个 commit,假如不是,请 rebase 后再提交 MR,不要一堆无用的、试验性的 commit。
+
+好处:从引擎的整体 commit 历史来看,会很清晰,**每个 commit 完成一件确定的事,changelog 也能自动生成**。另外,假如因为某个 commit 导致了 bug,也很容易通过 rebase drop 等方式快速修复。
+
+## 分支用途
+
+- main 分支,最稳定的分支,跟 npm latest 包的内容保持一致
+- develop 分支,开发分支,拥有最新的、已经验证过的 feature / bugfix,Pull Request 的**目标合入分支**
+- release 分支
+ - 正式发布分支,命名规则为 release/x.y.z,一般从 develop 拉出来进行发布,x.y.z 为待发布的版本号
+ - beta 发布分支,命名规则为 release/x.y.z-beta(\.\d+)?,可以快速验证修改,发布 npm beta 版本。
+
+验证通过后,因为 beta 发布分支上会存在无用的 commit(比如 lerna 修改 package.json 这种),所以不直接 PR 到 develop,而是从 develop 拉分支,从 beta 发布分支 cherry pick 有用的 commit 到新分支,然后 PR 到 develop。
+
+## 引擎发布机制
+
+日常迭代先从 develop 拉分支,然后自测、单测通过后,提交 PR 到 develop 分支,由发布负责人基于 develop 拉 release/1.0.z 分支~
+
+### 版本规划
+
+> 此处是理想节奏,实际情况可能会有调整
+
+- 日常迭代 2 周,一般月中或月底,发版日两天前发最后一个 beta 版本,原则上不接受新 pr,灰度 2 天后,发正式版。
+- 特殊情况紧急迭代随时发
+- 大 Feature 迭代,每年 2 - 4 次
+
+
+### 发布步骤
+> **发布需要权限,如果提 PR 之后着急发布可以**[**加入贡献者交流群**](../participate/#核心贡献者交流)**。**
+
+#### 发正式版
+步骤如下(以发布 1.0.0 版本为例):
+
+1. git checkout develop
+ ```bash
+ git checkout develop
+ ```
+2. 创建 release 分支
+ ```bash
+ git checkout -b release/1.0.0
+ ```
+3. build
+ ```bash
+ npm run build
+ ```
+4. 发布到 npm
+ ```bash
+ npm run pub
+ ```
+5. 同步到 tnpm 源 & alifd CDN & uipaas CDN(此步骤将发布在 npm 源的包同步到阿里内网源,因为 alifd cdn 将依赖内网 npm 源)
+ ```bash
+ tnpm run sync
+ tnpm run syncOss
+ ```
+6. 更新[发布日志](https://github.com/alibaba/lowcode-engine/releases)
+7. 合并 release/x.x.x 到 main 分支
+8. 合并 main 分支到 develop 分支
+
+如果是发布 beta 版本,步骤如下(以发布 1.0.1 版本为例):
+
+#### 发某 y 位版本首个 beta,如 1.1.0-beta.0
+1. 拉 develop 分支
+ ```bash
+ git checkout develop
+ ```
+ 更新到最新(如需)
+ ```bash
+ git pull
+ ```
+2. 拉 release 分支,此处以 1.1.0 版本做示例
+ ```bash
+ git checkout -b release/1.1.0-beta
+ git push --set-upstream origin release/1.1.0-beta
+ ```
+3. build
+ ```bash
+ npm run build
+ ```
+4. 发布,此处需有 @alilc scope 发包权限
+ ```bash
+ npm run pub:preminor
+ ```
+5. 同步到 tnpm 源 & alifd CDN & uipaas CDN
+ ```bash
+ tnpm run sync
+ tnpm run syncOss
+ ```
+
+#### 发某 z 位版本首个 beta,如 1.0.1-beta.0
+1. 拉 develop 分支
+ ```bash
+ git checkout develop
+ ```
+ 更新到最新(如需)
+ ```bash
+ git pull
+ ```
+2. 拉 release 分支,此处以 1.0.1 版本做示例
+ ```bash
+ git checkout -b release/1.0.1-beta
+ git push --set-upstream origin release/1.0.1-beta
+ ```
+3. build
+ ```bash
+ npm run build
+ ```
+4. 发布,此处需有 @alilc scope 发包权限
+ ```bash
+ npm run pub:prepatch
+ ```
+5. 同步到 tnpm 源 & alifd CDN & uipaas CDN
+ ```bash
+ tnpm run sync
+ tnpm run syncOss
+ ```
+
+#### 发某版本非首个 beta,如 1.0.1-beta.0 -> 1.0.1-beta.1
+1. 切换到 release 分支
+ ```bash
+ git checkout release/1.0.1-beta
+ ```
+2. 更新到 develop 分支最新代码
+ ```bash
+ git rebase origin/develop
+ ```
+3. build
+ ```bash
+ npm run build
+ ```
+4. 发布,此处需有 @alilc scope 发包权限 ***此处命令与发首个 beta 时有变化***
+ ```bash
+ npm run pub:prerelease
+ ```
+5. 同步到 tnpm 源 & alifd CDN & uipaas CDN
+ ```bash
+ tnpm run sync
+ tnpm run syncOss
+ ```
+
+
+
+## DEMO 发布机制
+1. **修改版本号**
+ 手动修改 package.json 的版本号
+2. **build**
+ ```bash
+ npm run build
+ ```
+3. publish(此步骤需要 npm 发包权限)
+ ```bash
+ npm run pub
+ ```
+ 如发 beta 版
+ ```bash
+ npm publish --tag beta
+ ```
+4. 同步到 tnpm 源 & alifd CDN & uipaas CDN
+ ```bash
+ tnpm run sync
+ tnpm run syncOss
+ ```
+
+**官网生效**
+需要在通过阿里内部系统更新 demo 版本
diff --git a/docs/docs/participate/index.md b/docs/docs/participate/index.md
new file mode 100644
index 0000000000..e09f2ddad2
--- /dev/null
+++ b/docs/docs/participate/index.md
@@ -0,0 +1,118 @@
+---
+title: 参与贡献
+sidebar_position: 0
+---
+
+### 环境准备
+
+开发 LowcodeEngine 需要 Node.js 16+。
+
+推荐使用 nvm 管理 Node.js,避免权限问题的同时,还能够随时切换当前使用的 Node.js 的版本。
+
+### 贡献低代码引擎
+
+#### clone 项目
+
+```
+git clone git@github.com:alibaba/lowcode-engine.git
+cd lowcode-engine
+```
+
+#### 安装依赖并构建
+
+```
+npm install && npm run setup
+```
+
+#### 调试环境配置
+
+本质上是将 demo 页面引入的几个 js/css 代理到 engine 项目,可以使用趁手的代理工具,这里推荐 [XSwitch](https://chrome.google.com/webstore/detail/xswitch/idkjhjggpffolpidfkikidcokdkdaogg?hl=en-US)。
+
+本地开发代理规则如下:
+```json
+{
+ "proxy": [
+ [
+ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/engine-core.js",
+ "http://localhost:5555/js/AliLowCodeEngine.js"
+ ],
+ [
+ "https://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/engine-core.css",
+ "http://localhost:5555/css/AliLowCodeEngine.css"
+ ],
+ [
+ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/js/react-simulator-renderer.js",
+ "http://localhost:5555/js/ReactSimulatorRenderer.js"
+ ],
+ [
+ "https?://uipaas-assets.com/prod/npm/@alilc/lowcode-engine/(.*)/dist/css/react-simulator-renderer.css",
+ "http://localhost:5555/css/ReactSimulatorRenderer.css"
+ ]
+ ]
+}
+```
+
+#### 开发
+
+```
+npm start
+```
+
+选择一个环境进行调试,例如[低代码引擎在线 DEMO](https://lowcode-engine.cn/demo/demo-general/index.html)
+
+开启代理之后,就可以进行开发调试了。
+
+
+### 贡献低代码引擎文档
+
+#### 开发文档
+
+在 lowcode-engine 目录下执行下面命令
+```
+cd docs
+
+npm start
+```
+
+#### 维护方式
+- 官方文档通过 github 管理文档源,官网文档与[主仓库 develop 分支](https://github.com/alibaba/lowcode-engine/tree/develop/docs)保持同步。
+- 点击每篇文档下发的 `编辑此页` 可直接定位到 github 中位置。
+- 欢迎 PR,文档 PR 也会作为贡献者贡献,会用于贡献度统计。
+- **文档同步到官方网站由官方人员进行操作**,如有需要可以通过 issue 或 贡献者群与相关人员沟通。
+- 为了提供更好的阅读和使用体验,文档中的图片文件会定期转换成可信的 CDN 地址。
+
+#### 文档格式
+
+本项目文档参考[文档编写指南](https://github.com/sparanoid/chinese-copywriting-guidelines)。
+
+使用 vscode 进行编辑的朋友可以安装 vscode 插件 [huacnlee.autocorrect](https://github.com/huacnlee/autocorrect) 辅助文档 lint。
+
+
+### 贡献低代码引擎生态
+
+相关源码详见[NPM 包对应源码位置汇总](/site/docs/guide/appendix/npms)
+
+开发调试方式详见[低代码生态脚手架 & 调试机制](/site/docs/guide/expand/editor/cli)
+
+### 发布
+
+PR 被合并之后,我们会尽快发布相关的正式版本或者 beta 版本。
+
+### 加入 Contributor 群
+提交过 Bugfix 或 Feature 类 PR 的同学,如果有兴趣一起参与维护 LowcodeEngine,我们提供了一个核心贡献者交流群。
+
+1. 可以通过[填写问卷](https://survey.taobao.com/apps/zhiliao/4YEtu9gHF)的方式,参与到其中。
+2. 填写问卷后加微信号 `wxidvlalalalal` (注明 github id)我们会拉你到群里。
+
+如果你不知道可以贡献什么,可以到源码里搜 TODO 或 FIXME 找找。
+
+为了使你能够快速上手和熟悉贡献流程,我们这里有个列表 [good first issues](https://github.com/alibaba/lowcode-engine/issues?q=is:open+is:issue+label:%22good+first+issue%22),里面有相对没那么笼统的漏洞,从这开始是个不错的选择。
+
+### PR 提交注意事项
+
+- lowcode-engine 仓库建议从 develop 创建分支,PR 指向 develop 分支。
+- 其他仓库从 main 分支创建分支,PR 指向 main 分支
+- 如果你修复了 bug 或者添加了代码,而这些内容需要测试,请添加测试!
+- 确保通过测试套件(yarn test)。
+- 请签订贡献者许可证协议(Contributor License Agreement)。
+ > 如已签署 CLA 仍被提示需要签署,[解决办法](/site/docs/faq/faq021)
\ No newline at end of file
diff --git a/docs/docs/participate/meet.md b/docs/docs/participate/meet.md
new file mode 100644
index 0000000000..23226bf1cd
--- /dev/null
+++ b/docs/docs/participate/meet.md
@@ -0,0 +1,55 @@
+---
+title: 开源社区例会
+sidebar_position: 0
+---
+
+## **简介**
+
+低代码引擎开源社区致力于共同推动低代码技术的发展和创新。本社区汇集了低代码技术领域的开发者、技术专家和行业观察者,通过定期的例会来交流思想、分享经验、讨论新技术,并探索低代码技术的未来发展方向。
+
+## 参与要求
+
+为了确保例会的质量和效果,我们建议以下人员参加:
+
+- **已参与低代码引擎贡献的成员**:那些对低代码引擎有实际贡献的社区成员。
+- **参考贡献指南**:可查阅[贡献指南](https://lowcode-engine.cn/site/docs/participate/)获取更多信息。
+- **提供过优秀建议的成员**:那些在过去为低代码引擎提供过有价值建议的成员。
+
+## **时间周期**
+
+- **周期性**:月例会
+
+### **特别说明**
+
+- 例会周期可根据成员反馈进行调整。如果讨论的议题较多,可增加例会频率;若议题较少,单次例会可能取消。若多次取消,可能会暂停例会。
+
+## **例会流程**
+
+### **准备阶段**
+
+- **定期确定议题**:会前一周确定下一次会议的议题。
+- **分发会议通知**:提前发送会议时间、议程和参与方式。
+
+### **会议阶段**
+
+- **开场和介绍**:简短开场和自我介绍,特别是新成员加入时。
+- **议题讨论**:按照议程进行议题讨论,每个议题分配一定时间,并留足够时间供讨论和提问。
+- **记录要点和决定**:记录讨论要点、决策和任何行动事项。
+
+### **后续阶段**
+
+- **分享会议纪要**:会后将会议纪要和行动计划分发给所有成员。
+- **执行和跟进**:根据会议中的讨论和决策执行相关任务,并在下次会议中进行跟进汇报。
+
+## **开源例会议题**
+
+开源例会议题包括但不限于:
+
+- **共建低代码行业发展**:探讨通过开源社区合作加速低代码行业发展。
+- **改进建议和反馈收集**:讨论社区成员对低代码引擎的使用体验和改进建议。
+- **前端技术与低代码的结合**:针对前端开发者,讨论将前端技术与低代码引擎结合的方式。
+- **低代码业务场景和经验分享**:邀请社区成员分享低代码引擎的实际应用经验。
+- **低代码技术原理介绍**:深入理解低代码引擎的技术原理和实现方式。
+- **低代码引擎的最新进展**:分享低代码引擎的最新进展,包括新版本发布和新功能实现等。
+- **低代码技术的未来展望**:讨论低代码技术的未来发展方向。
+- **最新低代码平台功能和趋势分析**:分享和讨论当前低代码平台的新功能、趋势和发展方向。
\ No newline at end of file
diff --git a/docs/docs/specs/assets-spec.md b/docs/docs/specs/assets-spec.md
new file mode 100644
index 0000000000..5a91b8dde3
--- /dev/null
+++ b/docs/docs/specs/assets-spec.md
@@ -0,0 +1,689 @@
+---
+title: 《低代码引擎资产包协议规范》
+sidebar_position: 2
+---
+## 1 介绍
+
+### 1.1 本协议规范涉及的问题域
+
+- 定义本协议版本号规范
+- 定义本协议中每个子规范需要被支持的 Level
+- 定义本协议相关的领域名词
+- 定义低代码资产包协议版本号规范(A)
+- 定义低代码资产包协议组件及依赖资源描述规范(A)
+- 定义低代码资产包协议组件描述资源加载规范(A)
+- 定义低代码资产包协议组件在面板展示规范(AA)
+
+### 1.2 协议草案起草人
+
+- 撰写:金禅、璿玑、彼洋
+- 审阅:力皓、絮黎、光弘、戊子、潕量、游鹿
+
+### 1.3 版本号
+
+1.1.0
+
+### 1.4 协议版本号规范(A)
+
+本协议采用语义版本号,版本号格式为 `major.minor.patch` 的形式。
+
+- major 是大版本号:用于发布不向下兼容的协议格式修改
+- minor 是小版本号:用于发布向下兼容的协议功能新增
+- patch 是补丁号:用于发布向下兼容的协议问题修正
+
+### 1.5 协议中子规范 Level 定义
+
+| 规范等级 | 实现要求 |
+| -------- | ------------------------------------------------------------ |
+| A | 基础规范,低代码引擎核心层支持; |
+| AA | 推荐规范,由低代码引擎官方插件、setter 支持。 |
+| AAA | 参考规范,需由基于引擎的上层搭建平台支持,实现可参考该规范。 |
+
+### 1.6 名词术语
+
+- **资产包**: 低代码引擎加载资源的动态数据集合,主要包含组件及其依赖的资源、组件低代码描述、动态插件/设置器资源等。
+
+### 1.7 背景
+
+根据低代码引擎的实现,一个组件要在引擎上渲染和配置,需要提供组件的 umd 资源以及组件的`低代码描述`,并且组件通常都是以集合的形式被引擎消费的;除了组件之外,还有组件的依赖资源、引擎的动态插件/设置器等资源也需要注册到引擎中;因此我们定义了“低代码资产包”这个数据结构,来描述引擎所需加载的动态资源的集合。
+
+### 1.8 受众
+
+本协议适用于使用“低代码引擎”构建搭建平台的开发者,通过本协议的定义来进行资源的分类和加载。阅读及使用本协议,需要对低代码搭建平台的交互和实现有一定的了解,对前端开发相关技术栈的熟悉也会有帮助,协议中对通用的前端相关术语不会做进一步的解释说明。
+
+## 2 协议结构
+
+协议最顶层结构如下,包含 7 方面的描述内容:
+
+- version { String } 当前协议版本号
+- packages { Array } 低代码编辑器中加载的资源列表
+- components { Array } 所有组件的描述协议列表
+- sort { Object } 用于描述组件面板中的 tab 和 category
+- plugins { Array } 设计器插件描述协议列表
+- setters { Array } 设计器中设置器描述协议列表
+- extConfig { Object } 平台自定义扩展字段
+
+### 2.1 version (A)
+
+定义当前协议 schema 的版本号;
+
+| 根属性名称 | 类型 | 说明 | 变量支持 | 默认值 |
+| ---------- | ------ | ---------- | -------- | ------ |
+| version | String | 协议版本号 | - | 1.1.0 |
+
+### 2.2 packages (A)
+
+定义低代码编辑器中加载的资源列表,包含公共库和组件 (库) cdn 资源等;
+
+| 字段 | 字段描述 | 字段类型 | 规范等级 | 备注 |
+| -------------------- | --------------------------------------------------------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------- |
+| packages[].id? | 资源唯一标识 | String | A | 资源唯一标识,如果为空,则以 package 为唯一标识 |
+| packages[].title? | 资源标题 | String | A | 资源标题 |
+| packages[].package | npm 包名 | String | A | 组件资源唯一标识 |
+| packages[].version | npm 包版本号 | String | A | 组件资源版本号 |
+| packages[].type | 资源包类型 | String | AA | 取值为: proCode(源码)、lowCode(低代码,默认为 proCode |
+| packages[].schema | 低代码组件 schema 内容 | object | AA | 取值为: proCode(源码)、lowCode(低代码) |
+| packages[].deps | 当前资源包的依赖资源的唯一标识列表 | Array | A | 唯一标识为 id 或者 package 对应的值 |
+| packages[].library | 作为全局变量引用时的名称,用来定义全局变量名 | String | A | 低代码引擎通过该字段获取组件实例 |
+| packages[].editUrls | 组件编辑态视图打包后的 CDN url 列表,包含 js 和 css | Array | A | 低代码引擎编辑器会加载这些 url |
+| packages[].urls | 组件渲染态视图打包后的 CDN url 列表,包含 js 和 css | Array | AA | 低代码引擎渲染模块会加载这些 url |
+| packages[].advancedEditUrls | 组件多个编辑态视图打包后的 CDN url 列表集合,包含 js 和 css | Object | AAA | 上层平台根据特定标识提取某个编辑态的资源,低代码引擎编辑器会加载这些资源,优先级高于 packages[].editUrls |
+| packages[].advancedUrls | 组件多个端的渲染态视图打包后的 CDN url 列表集合,包含 js 和 css | Object | AAA | 上层平台根据特定标识提取某个渲染态的资源, 低代码引擎渲染模块会加载这些资源,优先级高于 packages[].urls |
+| packages[].external | 当前资源在作为其他资源的依赖,在其他依赖打包时时是否被排除了(同 webpack 中 external 概念) | Boolean | AAA | 某些资源会被单独提取出来,是其他依赖的前置依赖,根据这个字段决定是否提前加载该资源 |
+| packages[].loadEnv | 指定当前资源加载的环境 | Array | AAA | 主要用于指定 external 资源加载的环境,取值为 design(设计态)、runtime(预览态) 中的一个或多个 |
+| packages[].exportSourceId | 标识当前 package 内容是从哪个 package 导出来的 | String | AAA | 此时 urls 无效 |
+| packages[].exportSourceLibrary | 标识当前 package 是从 window 上的哪个属性导出来的 | String | AAA | exportSourceId 的优先级高于exportSourceLibrary ,此时 urls 无效 |
+| packages[].async | 标识当前 package 资源加载在 window.library 上的是否是一个异步对象 | Boolean | A | async 为 true 时,需要通过 await 才能拿到真正内容 |
+| packages[].exportMode | 标识当前 package 从其他 package 的导出方式 | String | A | 目前只支持 `"functionCall"`, exportMode等于 `"functionCall"` 时,当前package 的内容以函数的方式从其他 package 中导出,具体导出接口如: (library: string, packageName: string, isRuntime?: boolean) => any | Promise, library 为当前 package 的 library, packageName 为当前的包名,返回值为当前 package 的导出内容 |
+
+描述举例:
+
+```json
+{
+ "packages": [
+ {
+ "title": "fusion 组件库",
+ "package": "@alifd/next",
+ "version": "1.23.0",
+ "urls": [
+ "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next.min.css",
+ "https://g.alicdn.com/code/lib/alifd__next/1.23.18/next-with-locales.min.js"
+ ],
+ "library": "Next"
+ },
+ {
+ "title": "Fusion 精品组件库",
+ "package": "@alife/fusion-ui",
+ "version": "0.1.5",
+ "editUrls": [
+ "https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/build/lowcode/view.js",
+ "https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/build/lowcode/view.css"
+ ],
+ "urls": [
+ "https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/dist/FusionUI.js",
+ "https://g.alicdn.com/code/npm/@alife/fusion-ui/0.1.7/dist/FusionUI.css"
+ ],
+ "library": "FusionUI"
+ },
+ {
+ "title": "低代码组件 A",
+ "id": "lcc-a",
+ "version": "0.1.5",
+ "type": "lowCode",
+ "schema": {
+ "componentsMap": [
+ {
+ "package": "@ali/vc-text",
+ "componentName": "Text",
+ "version": "4.1.1"
+ }
+ ],
+ "utils": [
+ {
+ "name": "dataSource",
+ "type": "npm",
+ "content": {
+ "package": "@ali/vu-dataSource",
+ "exportName": "dataSource",
+ "version": "1.0.4"
+ }
+ }
+ ],
+ "componentsTree": [
+ {
+ "defaultProps": {
+ "content": "这是默认值"
+ },
+ "methods": {
+ "__initMethods__": {
+ "compiled": "function (exports, module) { /*set actions code here*/ }",
+ "source": "function (exports, module) { /*set actions code here*/ }",
+ "type": "js"
+ }
+ },
+ "loopArgs": ["item", "index"],
+ "props": {
+ "mobileSlot": {
+ "type": "JSBlock",
+ "value": {
+ "children": [
+ {
+ "condition": true,
+ "hidden": false,
+ "isLocked": false,
+ "conditionGroup": "",
+ "componentName": "Text",
+ "id": "node_ockxiczf4m2",
+ "title": "",
+ "props": {
+ "maxLine": 0,
+ "showTitle": false,
+ "behavior": "NORMAL",
+ "content": {
+ "en-US": "Title",
+ "zh-CN": "页面标题",
+ "type": "i18n"
+ },
+ "__style__": {},
+ "fieldId": "text_kxiczgj4"
+ }
+ }
+ ],
+ "componentName": "Slot",
+ "props": {
+ "slotName": "mobileSlot",
+ "slotTitle": "mobile 容器"
+ }
+ }
+ },
+ "className": "component_k8e4naln",
+ "useDevice": false,
+ "fieldId": "symbol_k8bnubw4"
+ },
+ "condition": true,
+ "children": [
+ {
+ "condition": true,
+ "loopArgs": [null, null],
+ "componentName": "Text",
+ "id": "node_ockxiczf4m4",
+ "props": {
+ "maxLine": 0,
+ "showTitle": false,
+ "behavior": "NORMAL",
+ "content": {
+ "variable": "props.content",
+ "type": "variable",
+ "value": {
+ "use": "zh-CN",
+ "en-US": "Tips content",
+ "zh-CN": "这是一个低代码组件",
+ "type": "i18n"
+ }
+ },
+ "fieldId": "text_kxid1d9n"
+ }
+ }
+ ],
+ "propTypes": [
+ {
+ "defaultValue": "这是默认值",
+ "name": "content",
+ "title": "文本内容",
+ "type": "string"
+ }
+ ],
+ "componentName": "Component",
+ "id": "node_k8bnubvz",
+ "state": {}
+ }
+ ]
+ },
+ "library": "LCCA"
+ },
+ {
+ "title": "多端组件库",
+ "package": "@ali/atest1",
+ "version": "1.23.0",
+ "advancedUrls": {
+ "default": [
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css",
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/main.3354663.js"
+ ],
+ "mobile": [
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css",
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/main.mobile.3354663.js"
+ ],
+ "rax": [
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css",
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/main.rax.3354663.js"
+ ]
+ },
+ "advancedEditUrls": {
+ "design": [
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css",
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/editView.design.js"
+ ],
+ "default": [
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@alife/theme-254/1.24.0/@ali/atest1/1.0.0/theme.7c897c2.css",
+ "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/atest1/1.0.0/editView.js"
+ ]
+ },
+ "library": "Atest1"
+ },
+ {
+ "library":"UiPaaSServerless3",
+ "advancedUrls":{
+ "default":[
+ "https://g.alicdn.com/legao-comp/serverless3/1.1.0/env-staging-d224466e-0614-497d-8cd5-e4036dc50b70/main.js"
+ ]
+ },
+ "id":"UiPaaSServerless3-view",
+ "type":"procode",
+ "version":"1.0.0"
+ },
+ {
+ "package":"react-color",
+ "library":"ReactColor",
+ "id":"react-color",
+ "type":"procode",
+ "version":"2.19.3",
+ "async":true,
+ "exportMode":"functionCall",
+ "exportSourceId":"UiPaaSServerless3-view"
+ }
+ ]
+}
+```
+
+### 2.3 components (A)
+
+定义资产包中包含的所有组件的低代码描述的集合,分为“ComponentDescription”和“RemoteComponentDescription”(详见 2.6 TypeScript 定义):
+
+- ComponentDescription: 符合“组件描述协议”的数据,详见物料规范中`2.2.2 组件描述协议`部分;
+- RemoteComponentDescription 是将一个或多个 ComponentDescription 构建打包的 js 资源的描述,在浏览器中加载该资源后可获取到其中包含的每个组件的 ComponentDescription 的具体内容;
+
+### 2.4 sort (AA)
+
+定义组件列表分组
+
+| 根属性名称 | 类型 | 说明 | 变量支持 | 默认值 |
+| ----------------- | -------- | -------------------------------------------------------------------------------------------- | -------- | ---------------------------------------- |
+| sort.groupList | String[] | 组件分组,用于组件面板 tab 展示 | - | ['精选组件', '原子组件'] |
+| sort.categoryList | String[] | 组件面板中同一个 tab 下的不同区间用 category 区分,category 的排序依照 categoryList 顺序排列 | - | ['通用', '数据展示', '表格类', '表单类'] |
+
+### 2.5 plugins (AAA)
+
+自定义设计器插件列表
+
+| 根属性名称 | 类型 | 说明 | 变量支持 | 默认值 |
+| --------------------- | --------- | -------------------- | -------- | ------ |
+| plugins[].name | String | 插件名称 | - | - |
+| plugins[].title | String | 插件标题 | - | - |
+| plugins[].description | String | 插件描述 | - | - |
+| plugins[].docUrl | String | 插件文档地址 | - | - |
+| plugins[].screenshot | String | 插件截图地址 | - | - |
+| plugins[].tags | String[] | 插件标签分类 | - | - |
+| plugins[].keywords | String[] | 插件检索关键字 | - | - |
+| plugins[].reference | Reference | 插件引用的资源包信息 | - | - |
+
+### 2.6 setters (AAA)
+
+自定义设置器列表
+
+| 根属性名称 | 类型 | 说明 | 变量支持 | 默认值 |
+| --------------------- | --------- | ---------------------- | -------- | ------ |
+| setters[].name | String | 设置器组件名称 | - | - |
+| setters[].title | String | 设置器标题 | - | - |
+| setters[].description | String | 设置器描述 | - | - |
+| setters[].docUrl | String | 设置器文档地址 | - | - |
+| setters[].screenshot | String | 设置器截图地址 | - | - |
+| setters[].tags | String[] | 设置器标签分类 | - | - |
+| setters[].keywords | String[] | 设置器检索关键字 | - | - |
+| setters[].reference | Reference | 设置器引用的资源包信息 | - | - |
+
+### 2.7 extConfig (AAA)
+
+定义平台相关的扩展内容,用于存放平台自身实现的一些私有协议,以允许存量平台能够平滑地迁移至标准协议。extConfig 是一个 key-value 结构的对象,协议不会规定 extConfig 中的字段名称以及类型,完全自定义
+
+### 2.8 TypeScript 定义
+
+_组件低代码描述相关部分字段含义详见物料规范中`2.2.2 组件描述协议`部分;_
+
+```TypeScript
+
+/**
+ * 资产包协议
+ */
+export interface Assets {
+ /**
+ * 资产包协议版本号
+ */
+ version: string;
+ /**
+ * 资源列表
+ */
+ packages?: Array;
+ /**
+ * 所有组件的描述协议集合
+ */
+ components: Array;
+ /**
+ * 低代码编辑器插件集合
+ */
+ plugins?: Array;
+ /**
+ * 低代码设置器集合
+ */
+ setters?: Array;
+ /**
+ * 平台扩展配置
+ */
+ extConfig?: AssetsExtConfig;
+ /**
+ * 用于描述组件面板中的 tab 和 category
+ */
+ sort: ComponentSort;
+}
+
+export interface AssetsExtConfig{
+ [index: string]: any;
+}
+
+/**
+ * 描述组件面板中的 tab 和 category 排布
+ */
+export interface ComponentSort {
+ /**
+ * 用于描述组件面板的 tab 项及其排序,例如:["精选组件", "原子组件"]
+ */
+ groupList?: String[];
+ /**
+ * 组件面板中同一个 tab 下的不同区间用 category 区分,category 的排序依照 categoryList 顺序排列;
+ */
+ categoryList?: String[];
+}
+
+/**
+ * 定义资产包依赖信息
+ */
+export interface Package {
+ /**
+ * 唯一标识
+ */
+ id: string;
+ /**
+ * 包名
+ */
+ package: string;
+ /**
+ * 包版本号
+ */
+ version: string;
+ /**
+ * 资源类型
+ */
+ type: string;
+ /**
+ * 组件渲染态视图打包后的 CDN url 列表,包含 js 和 css
+ */
+ urls?: string[] | any;
+ /**
+ * 组件多个渲染态视图打包后的 CDN url 列表,包含 js 和 css,优先级高于 urls
+ */
+ advancedUrls?: ComplexUrls;
+ /**
+ * 组件编辑态视图打包后的 CDN url 列表,包含 js 和 css
+ */
+ editUrls?: string[] | any;
+ /**
+ * 组件多个编辑态视图打包后的 CDN url 列表,包含 js 和 css,优先级高于 editUrls
+ */
+ advancedEditUrls?: ComplexUrls;
+ /**
+ * 低代码组件的 schema 内容
+ */
+ schema?: ComponentSchema;
+ /**
+ * 当前资源所依赖的其他资源包的 id 列表
+ */
+ deps?: string[];
+ /**
+ * 指定当前资源加载的环境
+ */
+ loadEnv?: LoadEnv[];
+ /**
+ * 当前资源是否是 external 资源
+ */
+ external?: boolean;
+ /**
+ * 作为全局变量引用时的名称,和 webpack output.library 字段含义一样,用来定义全局变量名
+ */
+ library: string;
+ /**
+ * 组件描述导出名字,可以通过 window[exportName] 获取到组件描述的 Object 内容;
+ */
+ exportName?: string;
+ /**
+ * 标识当前 package 资源加载在 window.library 上的是否是一个异步对象
+ */
+ async?: boolean;
+ /**
+ * 标识当前 package 从其他 package 的导出方式
+ */
+ exportMode?: string;
+ /**
+ * 标识当前 package 内容是从哪个 package 导出来的
+ */
+ exportSourceId?: string;
+ /**
+ * 标识当前 package 是从 window 上的哪个属性导出来的
+ */
+ exportSourceLibrary?: string;
+}
+
+
+/**
+ * 复杂 urls 结构,同时兼容简单结构和多模态结构
+ */
+export type ComplexUrls = string[] | MultiModeUrls;
+
+/**
+ * 多模态资源
+ */
+export interface MultiModeUrls {
+ /**
+ * 默认的资源 url
+ */
+ default: string[];
+ /**
+ * 其他模态资源的 url
+ */
+ [index: string]: string[];
+}
+
+
+/**
+ * 资源加载环境种类
+ */
+export enum LoadEnv {
+ /**
+ * 设计态
+ */
+ design = "design",
+ /**
+ * 运行态
+ */
+ runtime = "runtime"
+}
+
+/**
+ * 低代码设置器描述
+ */
+export type SetterDescription = PluginDescription;
+
+/**
+ * 低代码插件器描述
+ */
+export interface PluginDescription {
+ /**
+ * 插件名称
+ */
+ name: string;
+ /**
+ * 插件标题
+ */
+ title: string;
+ /**
+ * 插件类型
+ */
+ type?: string;
+ /**
+ * 插件描述
+ */
+ description?: string;
+ /**
+ * 插件文档地址
+ */
+ docUrl: string;
+ /**
+ * 插件截图
+ */
+ screenshot: string;
+ /**
+ * 插件相关的标签
+ */
+ tags?: string[];
+ /**
+ * 插件关键字
+ */
+ keywords?: string[];
+ /**
+ * 插件引用的资源信息
+ */
+ reference: Reference;
+}
+
+/**
+ * 资源引用信息,Npm 的升级版本,
+ */
+export interface Reference {
+ /**
+ * 引用资源的 id 标识
+ */
+ id?: string;
+ /**
+ * 引用资源的包名
+ */
+ package?: string;
+ /**
+ * 引用资源的导出对象中的属性值名称
+ */
+ exportName: string;
+ /**
+ * 引用 exportName 上的子对象
+ */
+ subName: string;
+ /**
+ * 引用的资源主入口
+ */
+ main?: string;
+ /**
+ * 是否从引用资源的导出对象中获取属性值
+ */
+ destructuring: boolean;
+ /**
+ * 资源版本号
+ */
+ version: string;
+}
+
+
+/**
+ * 低代码片段
+ *
+ * 内容为组件不同状态下的低代码 schema (可以有多个),用户从组件面板拖入组件到设计器时会向页面 schema 中插入 snippets 中定义的组件低代码 schema
+ */
+export interface Snippet {
+ title: string;
+ screenshot?: string;
+ schema: ElementJSON;
+}
+
+/**
+ * 组件低代码描述
+ */
+export interface ComponentDescription {
+ componentName: string;
+ title: string;
+ description?: string;
+ docUrl: string;
+ screenshot: string;
+ icon?: string;
+ tags?: string[];
+ keywords?: string[];
+ devMode?: 'proCode' | 'lowCode';
+ npm: Npm;
+ props: Prop[];
+ configure: Configure;
+ /**
+ * 多模态下的组件描述, 优先级高于 configure
+ */
+ advancedConfigures: MultiModeConfigures;
+ snippets: Snippet[];
+ group: string;
+ category: string;
+ priority: number;
+ /**
+ * 组件引用的资源信息
+ */
+ reference: Reference;
+}
+
+export interface MultiModeConfigures {
+ default: Configure;
+ [index: string]: Configure;
+}
+
+/**
+ * 远程物料描述
+ */
+export interface RemoteComponentDescription {
+ /**
+ * 组件描述导出名字,可以通过 window[exportName] 获取到组件描述的 Object 内容;
+ */
+ exportName?: string;
+ /**
+ * 组件描述的资源链接;
+ */
+ url?: string;
+ /**
+ * 组件多模态描述的资源信息,优先级高于 url
+ */
+ advancedUrls?: ComplexUrl;
+ /**
+ * 组件(库)的 npm 信息;
+ */
+ package?: {
+ npm?: string;
+ };
+}
+
+export type ComplexUrl = string | MultiModeUrl
+
+export interface MultiModeUrl {
+ default: string;
+ [index: string]: string;
+}
+
+export interface ComponentSchema {
+ version: string;
+ componentsMap: ComponentsMap;
+ componentsTree: [ComponentTree];
+ i18n: I18nMap;
+ utils: UtilItem[];
+}
+
+```
+
+`ComponentSchema` 的定义见[低代码业务组件描述](./material-spec.md#221-组件规范)
diff --git a/docs/docs/specs/lowcode-spec.md b/docs/docs/specs/lowcode-spec.md
new file mode 100644
index 0000000000..c277214106
--- /dev/null
+++ b/docs/docs/specs/lowcode-spec.md
@@ -0,0 +1,1653 @@
+---
+title: 《低代码引擎搭建协议规范》
+sidebar_position: 0
+---
+
+## 1 介绍
+
+### 1.1 本协议规范涉及的问题域
+
+- 定义本协议版本号规范
+- 定义本协议中每个子规范需要被支持的 Level
+- 定义本协议相关的领域名词
+- 定义搭建基础协议版本号规范(A)
+- 定义搭建基础协议组件映射关系规范(A)
+- 定义搭建基础协议组件树描述规范(A)
+- 定义搭建基础协议国际化多语言支持规范(AA)
+- 定义搭建基础协议无障碍访问规范(AAA)
+
+
+### 1.2 协议草案起草人
+
+- 撰写:月飞、康为、林熠
+- 审阅:大果、潕量、九神、元彦、戊子、屹凡、金禅、前道、天晟、戊子、游鹿、光弘、力皓
+
+
+### 1.3 版本号
+
+1.1.0
+
+### 1.4 协议版本号规范(A)
+
+本协议采用语义版本号,版本号格式为 `major.minor.patch` 的形式。
+
+- major 是大版本号:用于发布不向下兼容的协议格式修改
+- minor 是小版本号:用于发布向下兼容的协议功能新增
+- patch 是补丁号:用于发布向下兼容的协议问题修正
+
+
+### 1.5 协议中子规范 Level 定义
+
+| 规范等级 | 实现要求 |
+| -------- | ---------------------------------------------------------------------------------- |
+| A | 强制规范,必须实现;违反此类规范的协议描述数据将无法写入物料中心,不支持流通。 |
+| AA | 推荐规范,推荐实现;遵守此类规范有助于业务未来的扩展性和跨团队合作研发效率的提升。 |
+| AAA | 参考规范,根据业务场景实际诉求实现;是集团层面鼓励的技术实现引导。 |
+
+
+### 1.6 名词术语
+
+#### 1.6.1 物料系统名词
+
+- **基础组件(Basic Component)**:前端领域通用的基础组件,阿里巴巴前端委员会官方指定的基础组件库是 Fusion Next/AntD。
+- **图表组件(Chart Component)**:前端领域通用的图表组件,有代表性的图表组件库有 BizCharts。
+- **业务组件(Business Component)**:业务领域内基于基础组件之上定义的组件,可能会包含特定业务域的交互或者是业务数据,对外仅暴露可配置的属性,且必须发布到公域(如阿里 NPM);在同一个业务域内可以流通,但不需要确保可以跨业务域复用。
+ - **低代码业务组件(Low-Code Business Component)**:通过低代码编辑器搭建而来,有别于源码开发的业务组件,属于业务组件中的一种类型,遵循业务组件的定义;同时低代码业务组件还可以通过低代码编辑器继续多次编辑。
+- **布局组件(Layout Component)**:前端领域通用的用于实现基础组件、图表组件、业务组件之间各类布局关系的组件,如三栏布局组件。
+- **区块(Block)**:通过低代码搭建的方式,将一系列业务组件、布局组件进行嵌套组合而成,不对外提供可配置的属性。可通过 区块容器组的包裹,实现区块内部具备有完整的样式、事件、生命周期管理、状态管理、数据流转机制。能独立存在和运行,可通过复制 schema 实现跨页面、跨应用的快速复用,保障功能和数据的正常。
+- **页面(Page)**:由组件 + 区块组合而成。由页面容器组件包裹,可描述页面级的状态管理和公共函数。
+- **模板(Template)**:特定垂直业务领域内的业务组件、区块可组合为单个页面,或者是再配合路由组合为多个页面集,统称为模板。
+
+
+#### 1.6.2 低代码搭建系统名词
+
+- **搭建编辑器**:使用可视化的方式实现页面搭建,支持组件 UI 编排、属性编辑、事件绑定、数据绑定,最终产出符合搭建基础协议规范的数据。
+ - **属性面板**:低代码编辑器内部用于组件、区块、页面的属性编辑、事件绑定、数据绑定的操作面板。
+ - **画布面板**:低代码编辑器内部用于 UI 编排的操作面板。
+ - **大纲面板**:低代码编辑器内部用于页面组件树展示的面板。
+- **编辑器框架**:搭建编辑器的基础框架,包含主题配置机制、插件机制、setter 控件机制、快捷键管理、扩展点管理等底层基础设施。
+- **入料模块**:专注于物料接入,能自动扫描、解析源码组件,并最终产出一份符合《低代码引擎物料协议规范》的 Schema JSON。
+- **编排模块**:专注于 Schema 可视化编排,以可视化的交互方式提供页面结构编排服务,并最终产出一份符合《低代码搭建基础协议规范》的 Schema JSON。
+- **渲染模块**:专注于将 Schema JSON 渲染为 UI 界面,最终呈现一个可交互的页面。
+- **出码模块 Schema2Code**:专注于通过 Schema JSON 生成高质量源代码,将符合《低代码搭建基础协议规范》的 Schema JSON 数据分别转化为面向 React / Rax / 阿里小程序等终端可渲染的代码。
+- **事件绑定**:是指为某个组件的某个事件绑定相关的事件处理动作,比如为某个组件的**点击事件**绑定**一段处理函数**或**响应动作**(比如弹出对话框),每个组件可绑定的事件由该组件自行定义。
+- **数据绑定**:是指为某个组件的某个属性绑定用于该属性使用的数据。
+- **生命周期**: 一般指某个对象的生老病死,本文中指某个实体(组件、容器、区块等等)的创建、加载、显示、销毁等关键生命阶段的统称。
+
+### 1.7 背景
+
+- **协议目标**:通过约束低代码引擎的搭建协议规范,让上层低代码编辑器的产出物(低代码业务组件、区块、应用)保持一致性,可跨低代码研发平台进行流通而提效,亦不阻碍集团业务间融合的发展。
+- **协议通**:
+ - 协议顶层结构统一
+ - 协议 schema 具备有完整的描述能力,包含版本、国际化、组件树、组件映射关系等;
+ - 顶层属性 key、value 值的格式,必须保持一致;
+ - 组件树描述统一
+ - 源码组件描述;
+ - 页面、区块、低代码业务组件这三种容器组件的描述;
+ - 数据流描述,包含数据请求、数据状态管理、数据绑定描述;
+ - 事件描述,包含统一事件上下文、统一搭建 API;
+- **物料通**:指在相同领域内的不同搭建产品,可直接使用的物料。比如模版、区块、组件;
+
+### 1.8 受众
+
+本协议适用于所有使用低代码搭建平台来开发页面或组件的开发者,以及围绕此协议的相关工具或工程化方案的开发者。阅读及使用本协议,需要对低代码搭建平台的交互和实现有一定的了解,对前端开发相关技术栈的熟悉也会有帮助,协议中对通用的前端相关术语不会做进一步的解释说明。
+
+### 1.9 使用范围
+
+本协议描述的是低代码搭建平台产物(应用、页面、区块、组件)的 schema 结构,以及实现其数据状态更新(内置 api)、能力扩展、国际化等方面完整,只在低代码搭建场景下可用;
+
+### 1.10 协议目标
+
+一套面向开发者的 schema 规范,用于规范化约束搭建编辑器的输出,以及渲染模块和出码模块的输入,将搭建编辑器、渲染模块、出码模块解耦,保障搭建编辑器、渲染模块、出码模块的独立升级。
+
+### 1.11 设计说明
+
+- **语义化**:语义清晰,简明易懂,可读性强。
+- **渐进性描述**:搭建的本质是通过 源码组件 进行嵌套组合,从小往大、依次组合生成 组件、区块、页面,最终通过云端构建生成 应用 的过程。因此在搭建基础协议中,我们需要知道如何去渐进性的描述组件、区块、页面、应用这 4 个实体概念。
+- **生成标准源码**:明确每一个属性与源码对应的转换关系,可生成跟手写无差异的高质量标准源代码。
+- **可流通性**:产物能在不同搭建产品中流通,不涉及任何私域数据存储。
+- **面向多端**:不能仅面向 React,还有小程序等多端。
+- **支持国际化&无障碍访问标准的实现**
+
+
+## 2 协议结构
+
+协议最顶层结构如下:
+
+- version { String } 当前协议版本号
+- componentsMap { Array } 组件映射关系
+- componentsTree { Array } 描述模版/页面/区块/低代码业务组件的组件树
+- utils { Array } 工具类扩展映射关系
+- i18n { Object } 国际化语料
+- constants { Object } 应用范围内的全局常量
+- css { string } 应用范围内的全局样式
+- config: { Object } 当前应用配置信息
+- meta: { Object } 当前应用元数据信息
+- dataSource: { Array } 当前应用的公共数据源
+- router: { Object } 当前应用的路由配置信息
+- pages: { Array } 当前应用的所有页面信息
+
+描述举例:
+
+```json
+{
+ "version": "1.0.0", // 当前协议版本号
+ "componentsMap": [{ // 组件描述
+ "componentName": "Button",
+ "package": "@alifd/next",
+ "version": "1.0.0",
+ "destructuring": true,
+ "exportName": "Select",
+ "subName": "Button"
+ }],
+ "utils": [{
+ "name": "clone",
+ "type": "npm",
+ "content": {
+ "package": "lodash",
+ "version": "0.0.1",
+ "exportName": "clone",
+ "subName": "",
+ "destructuring": false,
+ "main": "/lib/clone"
+ }
+ }, {
+ "name": "moment",
+ "type": "npm",
+ "content": {
+ "package": "@alifd/next",
+ "version": "0.0.1",
+ "exportName": "Moment",
+ "subName": "",
+ "destructuring": true,
+ "main": ""
+ }
+ }],
+ "componentsTree": [{ // 描述内容,值类型 Array
+ "id": "page1",
+ "componentName": "Page", // 单个页面,枚举类型 Page|Block|Component
+ "fileName": "Page1",
+ "props": {},
+ "css": "body {font-size: 12px;} .table { width: 100px;}",
+ "children": [{
+ "componentName": "Div",
+ "props": {
+ "className": ""
+ },
+ "children": [{
+ "componentName": "Button",
+ "props": {
+ "prop1": 1234, // 简单 json 数据
+ "prop2": [{ // 简单 json 数据
+ "label": "选项 1",
+ "value": 1
+ }, {
+ "label": "选项 2",
+ "value": 2
+ }],
+ "prop3": [{
+ "name": "myName",
+ "rule": {
+ "type": "JSExpression",
+ "value": "/\w+/i"
+ }
+ }],
+ "valueBind": { // 变量绑定
+ "type": "JSExpression",
+ "value": "this.state.user.name"
+ },
+ "onClick": { // 动作绑定
+ "type": "JSFunction",
+ "value": "function(e) { console.log(e.target.innerText) }"
+ },
+ "onClick2": { // 动作绑定 2
+ "type": "JSExpression",
+ "value": "this.submit"
+ }
+ }
+ }]
+ }]
+ }],
+ "constants": {
+ "ENV": "prod",
+ "DOMAIN": "xxx.com"
+ },
+ "css": "body {font-size: 12px;} .table { width: 100px;}",
+ "config": { // 当前应用配置信息
+ "sdkVersion": "1.0.3", // 渲染模块版本
+ "historyMode": "hash", // 不推荐,推荐在 router 字段中配置
+ "targetRootID": "J_Container",
+ "layout": {
+ "componentName": "BasicLayout",
+ "props": {
+ "logo": "...",
+ "name": "测试网站"
+ },
+ },
+ "theme": {
+ // for Fusion use dpl defined
+ "package": "@alife/theme-fusion",
+ "version": "^0.1.0",
+ // for Antd use variable
+ "primary": "#ff9966"
+ }
+ },
+ "meta": { // 应用元数据信息,key 为业务自定义
+ "name": "demo 应用", // 应用中文名称,
+ "git_group": "appGroup", // 应用对应 git 分组名
+ "project_name": "app_demo", // 应用对应 git 的 project 名称
+ "description": "这是一个测试应用", // 应用描述
+ "spma": "spa23d", // 应用 spm A 位信息
+ "creator": "月飞",
+ "gmt_create": "2020-02-11 00:00:00", // 创建时间
+ "gmt_modified": "2020-02-11 00:00:00", // 修改时间
+ ...
+ },
+ "i18n": {
+ "zh-CN": {
+ "i18n-jwg27yo4": "你好",
+ "i18n-jwg27yo3": "中国"
+ },
+ "en-US": {
+ "i18n-jwg27yo4": "Hello",
+ "i18n-jwg27yo3": "China"
+ }
+ },
+ "router": {
+ "baseUrl": "/",
+ "historyMode": "hash", // 浏览器路由:browser 哈希路由:hash
+ "routes": [
+ {
+ "path": "home",
+ "page": "page1"
+ }
+ ]
+ },
+ "pages": [
+ {
+ "id": "page1",
+ "treeId": "page1"
+ }
+ ]
+}
+```
+
+### 2.1 协议版本号(A)
+
+定义当前协议 schema 的版本号,不同的版本号对应不同的渲染 SDK,以保障不同版本搭建协议产物的正常渲染;
+
+
+| 根属性名称 | 类型 | 说明 | 变量支持 | 默认值 |
+| ---------- | ------ | ---------- | -------- | ------ |
+| version | String | 协议版本号 | - | 1.0.0 |
+
+
+描述示例:
+
+```javascript
+{
+ "version": "1.0.0"
+}
+```
+
+### 2.2 组件映射关系(A)
+
+协议中用于描述 componentName 到公域组件映射关系的规范。
+
+
+| 参数 | 说明 | 类型 | 变量支持 | 默认值 |
+| --------------- | ---------------------- | ------------------------- | -------- | ------ |
+| componentsMap[] | 描述组件映射关系的集合 | **ComponentMap**[] | - | null |
+
+**ComponentMap 结构描述**如下:
+
+| 参数 | 说明 | 类型 | 变量支持 | 默认值 |
+| ------------- | ------------------------------------------------------------------------------------------------------ | ------- | -------- | ------ |
+| componentName | 协议中的组件名,唯一性,对应包导出的组件名,是一个有效的 **JS 标识符**,而且是大写字母打头 | String | - | - |
+| package | npm 公域的 package name | String | - | - |
+| version | package version | String | - | - |
+| destructuring | 使用解构方式对模块进行导出 | Boolean | - | - |
+| exportName | 包导出的组件名 | String | - | - |
+| subName | 下标子组件名称 | String | - | |
+| main | 包导出组件入口文件路径 | String | - | - |
+
+
+描述示例:
+
+```json
+{
+ "componentsMap": [{
+ "componentName": "Button",
+ "package": "@alifd/next",
+ "version": "1.0.0",
+ "destructuring": true
+ }, {
+ "componentName": "MySelect",
+ "package": "@alifd/next",
+ "version": "1.0.0",
+ "destructuring": true,
+ "exportName": "Select"
+ }, {
+ "componentName": "ButtonGroup",
+ "package": "@alifd/next",
+ "version": "1.0.0",
+ "destructuring": true,
+ "exportName": "Button",
+ "subName": "Group"
+ }, {
+ "componentName": "RadioGroup",
+ "package": "@alifd/next",
+ "version": "1.0.0",
+ "destructuring": true,
+ "exportName": "Radio",
+ "subName": "Group"
+ }, {
+ "componentName": "CustomCard",
+ "package": "@ali/custom-card",
+ "version": "1.0.0"
+ }, {
+ "componentName": "CustomInput",
+ "package": "@ali/custom",
+ "version": "1.0.0",
+ "main": "/lib/input",
+ "destructuring": true,
+ "exportName": "Input"
+ }]
+}
+```
+
+出码结果:
+
+```javascript
+// 使用解构方式,destructuring is true.
+import { Button } from '@alifd/next';
+
+// 使用解构方式,且 exportName 和 componentName 不同
+import { Select as MySelect } from '@alifd/next';
+
+// 使用解构方式,并导出其子组件
+import { Button } from '@alifd/next';
+const ButtonGroup = Button.Group;
+
+import { Radio } from '@alifd/next';
+const RadioGroup = Radio.Group;
+
+// 不使用解构方式进行导出
+import CustomCard from '@ali/custom-card';
+
+// 使用特定路径进行导出
+import { Input as CustomInput } from '@ali/custom/lib/input';
+
+```
+
+
+### 2.3 组件树描述(A)
+
+
+协议中用于描述搭建出来的组件树结构的规范,整个组件树的描述由**组件结构**&**容器结构**两种结构嵌套构成。
+
+- 组件结构:描述单个组件的名称、属性、子集的结构;
+- 容器结构:描述单个容器的数据、自定义方法、生命周期的结构,用于将完整页面进行模块化拆分。
+
+与源码对应的转换关系如下:
+
+- 组件结构:转换成一个 .jsx 文件内 React Class 类 render 函数返回的 **jsx** 代码。
+- 容器结构:将转换成一个标准文件,如 React 的 jsx 文件,export 一个 React Class,包含生命周期定义、自定义方法、事件属性绑定、异步数据请求等。
+
+#### 2.3.1 基础结构描述 (A)
+
+此部分定义了组件结构、容器结构的公共基础字段。
+
+> 阅读时可先跳到后续章节,待需要时回来参考阅读
+
+##### 2.3.1.1 Props 结构描述
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 | 备注 |
+| ----------- | ------------ | ------ | -------- | ------ | ------------------------------------- |
+| id | 组件 ID | String | ✅ | - | 系统属性 |
+| className | 组件样式类名 | String | ✅ | - | 系统属性,支持变量表达式 |
+| style | 组件内联样式 | Object | ✅ | - | 系统属性,单个内联样式属性值 |
+| ref | 组件 ref 名称 | String | ✅ | - | 可通过 `this.$(ref)` 获取组件实例 |
+| extendProps | 组件继承属性 | 变量 | ✅ | - | 仅支持变量绑定,常用于继承属性对象 |
+| ... | 组件私有属性 | - | - | - | |
+
+##### 2.3.1.2 css/less/scss 样式描述
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 |
+| ------------- | -------------------------------------------------------------------------- | ------ | -------- | ------ |
+| css/less/scss | 用于描述容器组件内部节点的样式,对应生成一个独立的样式文件,不支持 @import | String | - | null |
+
+描述示例:
+
+```json
+{
+ "css": "body {font-size: 12px;} .table { width: 100px; }"
+}
+```
+
+##### 2.3.1.3 ComponentDataSource 对象描述
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 | 备注 |
+| ----------- | ---------------------- | -------------------------------------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------- |
+| list[] | 数据源列表 | **ComponentDataSourceItem**[] | - | - | 成为为单个请求配置, 内容定义详见 [ComponentDataSourceItem 对象描述](#2314-componentdatasourceitem-对象描述) |
+| dataHandler | 所有请求数据的处理函数 | Function | - | - | 详见 [dataHandler Function 描述](#2317-datahandler-function 描述) |
+
+##### 2.3.1.4 ComponentDataSourceItem 对象描述
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 | 备注 |
+| -------------- | ---------------------------- | ---------------------------------------------------- | -------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| id | 数据请求 ID 标识 | String | - | - | |
+| isInit | 是否为初始数据 | Boolean | ✅ | true | 值为 true 时,将在组件初始化渲染时自动发送当前数据请求 |
+| isSync | 是否需要串行执行 | Boolean | ✅ | false | 值为 true 时,当前请求将被串行执行 |
+| type | 数据请求类型 | String | - | fetch | 支持四种类型:fetch/mtop/jsonp/custom |
+| shouldFetch | 本次请求是否可以正常请求 | (options: ComponentDataSourceItemOptions) => boolean | - | ```() => true``` | function 参数参考 [ComponentDataSourceItemOptions 对象描述](#2315-componentdatasourceitemoptions-对象描述) |
+| willFetch | 单个数据结果请求参数处理函数 | Function | - | options => options | 只接受一个参数(options),返回值作为请求的 options,当处理异常时,使用原 options。也可以返回一个 Promise,resolve 的值作为请求的 options,reject 时,使用原 options |
+| requestHandler | 自定义扩展的外部请求处理器 | Function | - | - | 仅 type='custom' 时生效 |
+| dataHandler | request 成功后的回调函数 | Function | - | `response => response.data`| 参数:请求成功后 promise 的 value 值 ||
+| errorHandler | request 失败后的回调函数 | Function | - | - | 参数:请求出错 promise 的 error 内容 |
+| options {} | 请求参数 | **ComponentDataSourceItemOptions**| - | - | 每种请求类型对应不同参数,详见 | 每种请求类型对应不同参数,详见 [ComponentDataSourceItemOptions 对象描述](#2315-componentdatasourceitemoptions-对象描述) |
+
+**关于 dataHandler 于 errorHandler 的细节说明:**
+
+request 返回的是一个 promise,dataHandler 和 errorHandler 遵循 Promise 对象的 then 方法,实际使用方式如下:
+
+```ts
+// 伪代码
+try {
+ const result = await request(fetchConfig).then(dataHandler, errorHandler);
+ dataSourceItem.data = result;
+ dataSourceItem.status = 'success';
+} catch (err) {
+ dataSourceItem.error = err;
+ dataSourceItem.status = 'error';
+}
+```
+**注意:**
+- dataHandler 和 errorHandler 只会走其中的一个回调
+- 它们都有修改 promise 状态的机会,意味着可以修改当前数据源最终状态
+- 最后返回的结果会被认为是当前数据源的最终结果,如果被 catch 了,那么会认为数据源请求出错
+- dataHandler 会有默认值,考虑到返回结果入参都是 response 完整对象,默认值会返回 `response.data`,errorHandler 没有默认值
+
+
+##### 2.3.1.5 ComponentDataSourceItemOptions 对象描述
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 | 备注 |
+| ------- | ------------ | ------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------- |
+| uri | 请求地址 | String | ✅ | - | |
+| params | 请求参数 | Object | ✅ | {} | 当前数据源默认请求参数(在运行时会被实际的 load 方法的参数替换,如果 load 的 params 没有则会使用当前 params) |
+| method | 请求方法 | String | ✅ | GET | |
+| isCors | 是否支持跨域 | Boolean | ✅ | true | 对应 `credentials = 'include'` |
+| timeout | 超时时长 | Number | ✅ | 5000 | 单位 ms |
+| headers | 请求头信息 | Object | ✅ | - | 自定义请求头 |
+
+
+
+##### 2.3.1.6 ComponentLifeCycles 对象描述
+
+生命周期对象,schema 面向多端,不同 DSL 有不同的生命周期方法:
+
+- React:对于中后台 PC 物料,已明确使用 React 作为最终渲染框架,因此提案采用 [React16 标准生命周期方法](https://reactjs.org/docs/react-component.html)标准来定义生命周期方法,降低理解成本,支持生命周期如下:
+ - constructor(props, context)
+ - 说明:初始化渲染时执行,常用于设置 state 值。
+ - render()
+ - 说明:执行于容器组件 React Class 的 render 方法最前,常用于计算变量挂载到 this 对象上,供 props 上属性绑定。此 render() 方法不需要设置 return 返回值。
+ - componentDidMount()
+ - 说明:组件已加载
+ - componentDidUpdate(prevProps, prevState, snapshot)
+ - 说明:组件已更新
+ - componentWillUnmount()
+ - 说明:组件即将从 DOM 中移除
+ - componentDidCatch(error, info)
+ - 说明:组件捕获到异常
+
+该对象由一系列 key-value 组成,key 为生命周期方法名,value 为 JSFunction 的描述,详见下方示例:
+
+```json
+{
+ "componentDidMount": { // key 为上文中 React 的生命周期方法名
+ "type": "JSFunction", // type 目前仅支持 JSFunction
+ "value": "function() {\ // value 为 javascript 函数
+ console.log('did mount');\
+ }"
+ },
+ "componentWillUnmount": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log('will unmount');\
+ }"
+ }
+ ...
+},
+```
+
+
+##### 2.3.1.7 dataHandler Function 描述
+
+- 参数:为 dataMap 对象,包含字段如下:
+ - key: 数据 id
+ - value: 单个请求结果
+- 返回值:数据对象 data,将会在渲染引擎和 schemaToCode 中通过调用 `this.setState(...)` 将返回的数据对象生效到 state 中;支持返回一个 Promise,通过 `resolve(返回数据)`,常用于串行发送请求场景。
+
+##### 2.3.1.8 ComponentPropDefinition 对象描述
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 | 备注 |
+| ------------ | ---------- | -------------- | -------- | --------- | ----------------------------------------------------------------------------------------------------------------- |
+| name | 属性名称 | String | - | - | |
+| propType | 属性类型 | String\|Object | - | - | 具体值内容结构,参考《低代码引擎物料协议规范》内的“2.2.2.3 组件属性信息”中描述的**基本类型**和**复合类型** |
+| description | 属性描述 | String | - | '' | |
+| defaultValue | 属性默认值 | Any | - | undefined | 当 defaultValue 和 defaultProps 中存在同一个 prop 的默认值时,优先使用 defaultValue。 |
+
+范例:
+```json
+{
+ "propDefinitions": [{
+ "name": "title",
+ "propType": "string",
+ "defaultValue": "Default Title"
+ }, {
+ "name": "onClick",
+ "propType": "func"
+ }]
+ ...
+},
+```
+
+#### 2.3.2 组件结构描述(A)
+
+对应生成源码开发体系中 render 函数返回的 jsx 代码,主要描述有以下属性:
+
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 | 备注 |
+| ------------- | ---------------------- | ---------------- | -------- | ----------------- | ---------------------------------------------------------------------------------------------------------- |
+| id | 组件唯一标识 | String | - | | 可选,组件 id 由引擎随机生成(UUID),并保证唯一性,消费方为上层应用平台,在组件发生移动等场景需保持 id 不变 |
+| componentName | 组件名称 | String | - | Div | 必填,首字母大写,同 [componentsMap](#22-组件映射关系 a) 中的要求 |
+| props {} | 组件属性对象 | **Props**| - | {} | 必填,详见 | 必填,详见 [Props 结构描述](#2311-props-结构描述) |
+| condition | 渲染条件 | Boolean | ✅ | true | 选填,根据表达式结果判断是否渲染物料;支持变量表达式 |
+| loop | 循环数据 | Array | ✅ | - | 选填,默认不进行循环渲染;支持变量表达式 |
+| loopArgs | 循环迭代对象、索引名称 | [String, String] | | ["item", "index"] | 选填,仅支持字符串 |
+| children | 子组件 | Array | | | 选填,支持变量表达式 |
+
+
+描述举例:
+
+```json
+{
+ "componentName": "Button",
+ "props": {
+ "className": "btn",
+ "style": {
+ "width": 100,
+ "height": 20
+ },
+ "text": "submit",
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(e) {\
+ console.log('btn click')\
+ }"
+ }
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!!this.state.isshow"
+ },
+ "loop": [],
+ "loopArgs": ["item", "index"],
+ "children": []
+}
+```
+
+
+#### 2.3.3 容器结构描述 (A)
+
+容器是一类特殊的组件,在组件能力基础上增加了对生命周期对象、自定义方法、样式文件、数据源等信息的描述。包含**低代码业务组件容器 Component**、**区块容器 Block**、**页面容器 Page** 3 种。主要描述有以下属性:
+
+- 组件类型:componentName
+- 文件名称:fileName
+- 组件属性:props
+- state 状态管理:state
+- 生命周期 Hook 方法:lifeCycles
+- 自定义方法设置:methods
+- 异步数据源配置:dataSource
+- 条件渲染:condition
+- 样式文件:css/less/scss
+
+
+详细描述:
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 | 备注 |
+| --------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------- | -------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
+| componentName | 组件名称 | 枚举类型,包括`'Page'` (代表页面容器)、`'Block'` (代表区块容器)、`'Component'` (代表低代码业务组件容器) | - | 'Div' | 必填,首字母大写 |
+| fileName | 文件名称 | String | - | - | 必填,英文 |
+| props { } | 组件属性对象 | **Props** | - | {} | 必填,详见 [Props 结构描述](#2311-props-结构描述) |
+| static | 低代码业务组件类的静态对象 | | | | |
+| defaultProps | 低代码业务组件默认属性 | Object | - | - | 选填,仅用于定义低代码业务组件的默认属性 |
+| propDefinitions | 低代码业务组件属性类型定义 | **ComponentPropDefinition**[] | - | - | 选填,仅用于定义低代码业务组件的属性数据类型。详见 [ComponentPropDefinition 对象描述](#2318-componentpropdefinition-对象描述) |
+| condition | 渲染条件 | Boolean | ✅ | true | 选填,根据表达式结果判断是否渲染物料;支持变量表达式 |
+| state | 容器初始数据 | Object | ✅ | - | 选填,支持变量表达式 |
+| children | 子组件 | Array | - | | 选填,支持变量表达式 |
+| css/less/scss | 样式属性 | String | ✅ | - | 选填,详见 [css/less/scss 样式描述](#2312-csslessscss 样式描述) |
+| lifeCycles | 生命周期对象 | **ComponentLifeCycles** | - | - | 详见 [ComponentLifeCycles 对象描述](#2316-componentlifecycles-对象描述) |
+| methods | 自定义方法对象 | Object | - | - | 选填,对象成员为函数类型 |
+| dataSource {} | 数据源对象 | **ComponentDataSource**| - | - | 选填,异步数据源,详见 | - | - | 选填,异步数据源,详见 [ComponentDataSource 对象描述](#2313-componentdatasource-对象描述) |
+
+
+
+#### 完整描述示例
+
+描述示例 1:(正常 fetch/mtop/jsonp 请求):
+
+```json
+{
+ "componentName": "Block",
+ "fileName": "block-1",
+ "props": {
+ "className": "luna-page",
+ "style": {
+ "background": "#dd2727"
+ }
+ },
+ "children": [{
+ "componentName": "Button",
+ "props": {
+ "text": {
+ "type": "JSExpression",
+ "value": "this.state.btnText"
+ }
+ }
+ }],
+ "state": {
+ "btnText": "submit"
+ },
+ "css": "body {font-size: 12px;}",
+ "lifeCycles": {
+ "componentDidMount": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log('did mount');\
+ }"
+ },
+ "componentWillUnmount": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log('will unmount');\
+ }"
+ }
+ },
+ "methods": {
+ "testFunc": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log('test func');\
+ }"
+ }
+ },
+ "dataSource": {
+ "list": [{
+ "id": "list",
+ "isInit": true,
+ "type": "fetch/mtop/jsonp",
+ "options": {
+ "uri": "",
+ "params": {},
+ "method": "GET",
+ "isCors": true,
+ "timeout": 5000,
+ "headers": {}
+ },
+ "dataHandler": {
+ "type": "JSFunction",
+ "value": "function(data, err) {}"
+ }
+ }],
+ "dataHandler": {
+ "type": "JSFunction",
+ "value": "function(dataMap) { }"
+ }
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "!!this.state.isShow"
+ }
+}
+```
+
+描述示例 2:(自定义扩展请求处理器类型):
+
+```json
+{
+ "componentName": "Block",
+ "fileName": "block-1",
+ "props": {
+ "className": "luna-page",
+ "style": {
+ "background": "#dd2727"
+ }
+ },
+ ...
+ "dataSource": {
+ "list": [{
+ "id": "list",
+ "isInit": true,
+ "type": "custom",
+ "requestHandler": {
+ "type": "JSFunction",
+ "value": "this.utils.hsfHandler"
+ },
+ "options": {
+ "uri": "hsf://xxx",
+ "param1": "a",
+ "param2": "b",
+ ...
+ },
+ "dataHandler": {
+ "type": "JSFunction",
+ "value": "function(data, err) { }"
+ }
+ }],
+ "dataHandler": {
+ "type": "JSFunction",
+ "value": "function(dataMap) { }"
+ }
+ }
+}
+```
+
+#### 2.3.4 属性值类型描述(A)
+
+在上述**组件结构**和**容器结构**描述中,每一个属性所对应的值,除了传统的 JS 值类型(String、Number、Object、Array、Boolean)外,还包含有**节点类型**、**事件函数类型**、**变量类型**等多种复杂类型;接下来将对于复杂类型的详细描述方式进行详细介绍。
+
+##### 2.3.4.1 节点类型(A)
+
+通常用于描述组件的某一个属性为 **ReactNode** 或 **Function-Return-ReactNode** 的场景。该类属性的描述均以 **JSSlot** 的方式进行描述,详细描述如下:
+
+**ReactNode** 描述:
+
+| 参数 | 说明 | 值类型 | 默认值 | 备注 |
+| ----- | ---------- | --------------------- | -------- | -------------------------------------------------------------- |
+| type | 值类型描述 | String | 'JSSlot' | 固定值 |
+| value | 具体的值 | NodeSchema \| NodeSchema[] | null | 内容为 NodeSchema 类型,详见[组件结构描述](#232-组件结构描述(A)) |
+
+
+举例描述:如 **Card** 的 **title** 属性
+
+```json
+{
+ "componentName": "Card",
+ "props": {
+ "title": {
+ "type": "JSSlot",
+ "value": [{
+ "componentName": "Icon",
+ "props": {}
+ },{
+ "componentName": "Text",
+ "props": {}
+ }]
+ },
+ ...
+ }
+}
+
+```
+
+
+**Function-Return-ReactNode** 描述:
+
+| 参数 | 说明 | 值类型 | 默认值 | 备注 |
+| ------ | ---------- | --------------------- | -------- | -------------------------------------------------------------- |
+| type | 值类型描述 | String | 'JSSlot' | 固定值 |
+| value | 具体的值 | NodeSchema \| NodeSchema[] | null | 内容为 NodeSchema 类型,详见[组件结构描述](#232-组件结构描述 a) |
+| params | 函数的参数 | String[] | null | 函数的入参,其子节点可以通过 `this[参数名]` 来获取对应的参数。 |
+
+
+举例描述:如 **Table.Column** 的 **cell** 属性
+
+```json
+{
+ "componentName": "TabelColumn",
+ "props": {
+ "cell": {
+ "type": "JSSlot",
+ "params": ["value", "index", "record"],
+ "value": [{
+ "componentName": "Input",
+ "props": {}
+ }]
+ },
+ ...
+ }
+}
+
+```
+
+##### 2.3.4.2 事件函数类型(A)
+
+协议内的事件描述,主要包含**容器结构**的**生命周期**和**自定义方法**,以及**组件结构**的**事件函数类属性**三类。所有事件函数的描述,均以 **JSFunction** 的方式进行描述,保留与原组件属性、生命周期(React / 小程序)一致的输入参数,并给所有事件函数 binding 统一一致的上下文(当前组件所在容器结构的 **this** 对象)。
+
+**事件函数类型**的属性值描述如下:
+
+```json
+{
+ "type": "JSFunction",
+ "value": "function onClick(){\
+ console.log(123);\
+ }"
+}
+```
+
+描述举例:
+
+```json
+{
+ "componentName": "Block",
+ "fileName": "block1",
+ "props": {},
+ "state": {
+ "name": "lucy"
+ },
+ "lifeCycles": {
+ "componentDidMount": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log('did mount');\
+ }"
+ },
+ "componentWillUnmount": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log('will unmount');\
+ }"
+ }
+ },
+ "methods": {
+ "getNum": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log('名称是:' + this.state.name)\
+ }"
+ }
+ },
+ "children": [{
+ "componentName": "Button",
+ "props": {
+ "text": "按钮",
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function(e) {\
+ console.log(e.target.innerText);\
+ }"
+ }
+ }
+ }]
+}
+```
+
+##### 2.3.4.3 变量类型(A)
+
+在上述**组件结构** 或**容器结构**中,有多个属性的值类型是支持变量类型的,通常会通过变量形式来绑定某个数据,所有的变量表达式均通过 JSExpression 表达式,上下文与事件函数描述一致,表达式内通过 **this** 对象获取上下文;
+
+变量**类型**的属性值描述如下:
+
+
+- return 数字类型
+
+ ```json
+ {
+ "type": "JSExpression",
+ "value": "this.state.num"
+ }
+ ```
+- return 数字类型
+
+ ```json
+ {
+ "type": "JSExpression",
+ "value": "this.state.num - this.state.num2"
+ }
+ ```
+- return "8 万" 字符串类型
+
+ ```json
+ {
+ "type": "JSExpression",
+ "value": "`${this.state.num}万`"
+ }
+ ```
+- return "8 万" 字符串类型
+
+ ```json
+ {
+ "type": "JSExpression",
+ "value": "this.state.num + '万'"
+ }
+ ```
+- return 13 数字类型
+
+ ```json
+ {
+ "type": "JSExpression",
+ "value": "getNum(this.state.num, this.state.num2)"
+ }
+ ```
+- return true 布尔类型
+
+ ```json
+ {
+ "type": "JSExpression",
+ "value": "this.state.num > this.state.num2"
+ }
+ ```
+
+描述举例:
+
+```json
+{
+ "componentName": "Block",
+ "fileName": "block1",
+ "props": {},
+ "state": {
+ "num": 8,
+ "num2": 5
+ },
+ "methods": {
+ "getNum": {
+ "type": "JSFunction",
+ "value": "function(a, b){\
+ return a + b;\
+ }"
+ }
+ },
+ "children": [{
+ "componentName": "Button",
+ "props": {
+ "text": {
+ "type": "JSExpression",
+ "value": "this.getNum(this.state.num, this.state.num2) + '万'"
+ }
+ },
+ "condition": {
+ "type": "JSExpression",
+ "value": "this.state.num > this.state.num2"
+ }
+ }]
+}
+```
+
+##### 2.3.4.4 国际化多语言类型(AA)
+
+协议内的一些文本值内容,我们希望是和协议全局的国际化多语言语料是关联的,会按照全局国际化语言环境的不同使用对应的语料。所有国际化多语言值均以 **i18n** 结构描述。这样可以更为清晰且结构化得表达使用场景。
+
+**国际化多语言类型**的属性值类型描述如下:
+
+```typescript
+type Ti18n = {
+ type: 'i18n';
+ key: string; // i18n 结构中字段的 key 标识符
+ params?: Record; // 模版型 i18n 文案的入参,JSDataType 指代传统 JS 值类型
+}
+```
+
+其中 `key` 对应协议 `i18n` 内容的语料键值,`params` 为语料为字符串模板时的变量内容。
+
+假设协议已加入如下 i18n 内容:
+```json
+{
+ "i18n": {
+ "zh-CN": {
+ "i18n-jwg27yo4": "你好",
+ "i18n-jwg27yo3": "{name}博士"
+ },
+ "en-US": {
+ "i18n-jwg27yo4": "Hello",
+ "i18n-jwg27yo3": "Doctor {name}"
+ }
+ }
+}
+```
+
+**国际化多语言类型**简单范例:
+
+```json
+{
+ "type": "i18n",
+ "key": "i18n-jwg27yo4"
+}
+```
+
+**国际化多语言类型**模板范例:
+
+```json
+{
+ "type": "i18n",
+ "key": "i18n-jwg27yo3",
+ "params": {
+ "name": "Strange"
+ }
+}
+```
+
+描述举例:
+
+```json
+{
+ "componentName": "Button",
+ "props": {
+ "text": {
+ "type": "i18n",
+ "key": "i18n-jwg27yo4"
+ }
+ }
+}
+```
+
+
+#### 2.3.5 上下文 API 描述(A)
+
+在上述**事件类型描述**和**变量类型描述**中,在函数或 JS 表达式内,均可以通过 **this** 对象获取当前组件所在容器(React Class)的实例化对象,在搭建场景下的渲染模块和出码模块实现上,统一约定了该实例化 **this** 对象下所挂载的最小 API 集合,以保障搭建协议具备有一致的**数据流**和**事件上下文**。
+
+##### 2.3.5.1 容器 API:
+
+| 参数 | 说明 | 类型 | 备注 |
+| ----------------------------------- | --------------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------- |
+| **this {}** | 当前区块容器的实例对象 | Class Instance | - |
+| *this*.state | 三种容器实例的数据对象 state | Object | - |
+| *this*.setState(newState, callback) | 三种容器实例更新数据的方法 | Function | 这个 setState 通常会异步执行,详见下文 [setState](#setstate) |
+| *this*.customMethod() | 三种容器实例的自定义方法 | Function | - |
+| *this*.dataSourceMap {} | 三种容器实例的数据源对象 Map | Object | 单个请求的 id 为 key, value 详见下文 [DataSourceMapItem 结构描述](#datasourcemapitem-结构描述) |
+| *this*.reloadDataSource() | 三种容器实例的初始化异步数据请求重载 | Function | 返回 \ |
+| **this.page {}** | 当前页面容器的实例对象 | Class Instance | |
+| *this.page*.props | 读取页面路由,参数等相关信息 | Object | query 查询参数 { key: value } 形式;path 路径;uri 页面唯一标识;其它扩展字段 |
+| *this.page*.xxx | 继承 this 对象所有 API | | 此处 `xxx` 代指 `this.page` 中的其他 API |
+| **this.component {}** | 当前低代码业务组件容器的实例对象 | Class Instance | |
+| *this.component*.props | 读取低代码业务组件容器的外部传入的 props | Object | |
+| *this.component*.xxx | 继承 this 对象所有 API | | 此处 `xxx` 代指 `this.component` 中的其他 API |
+| **this.$(ref)** | 获取组件的引用(单个) | Component Instance | `ref` 对应组件上配置的 `ref` 属性,用于唯一标识一个组件;若有同名的,则会返回第一个匹配的。 |
+| **this.$$(ref)** | 获取组件的引用(所有同名的) | Array of Component Instances | `ref` 对应组件上配置的 `ref` 属性,用于唯一标识一个组件;总是返回一个数组,里面是所有匹配 `ref` 的组件的引用。 |
+
+##### setState
+
+`setState()` 将对容器 `state` 的更改排入队列,并通知低代码引擎需要使用更新后的 `state` 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式。
+
+请将 `setState()` 视为请求而不是立即更新组件的命令。为了更好的感知性能,低代码引擎会延迟调用它,然后通过一次传递更新多个组件。低代码引擎并不会保证 state 的变更会立即生效。
+
+`setState()`并不总是立即更新组件,它会批量推迟更新。这使得在调用用 `setState()` 后立即读取 `this.state` 成为了隐患。为了消除隐患,请使用 `setState` 的回调函数(`setState(updater, callback)`),`callback` 将在应用更新后触发。即,如下例所示:
+
+```js
+this.setState(newState, () => {
+ // 在这里更新已经生效了
+ // 可以通过 this.state 拿到更新后的状态
+ console.log(this.state);
+});
+
+// ⚠注意:这里拿到的并不是更新后的状态,这里还是之前的状态
+console.log(this.state);
+```
+
+如需基于之前的 `state` 来设置当前的 `state`,则可以将传递一个 `updater` 函数:`(state, props) => newState`,例如:
+
+```js
+this.setState((prevState) => ({ count: prevState.count + 1 }));
+```
+
+为了方便更新部分状态,`setState` 会将 `newState` 浅合并到新的 `state` 上。
+
+
+##### DataSourceMapItem 结构描述
+
+| 参数 | 说明 | 类型 | 备注 |
+| ------------ | -------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------ |
+| load(params) | 调用单个数据源 | Function | 当前参数 params 会替换 [ComponentDataSourceItemOptions 对象描述](#2315-componentdatasourceitemoptions-对象描述)中的 params 内容 |
+| status | 获取单个数据源上次请求状态 | String | loading、loaded、error、init |
+| data | 获取上次请求成功后的数据 | Any | |
+| error | 获取上次请求失败的错误对象 | Error 对象 | |
+
+备注:如果组件没有在区块容器内,而是直接在页面内,那么 `this === this.page`
+
+
+##### 2.3.5.2 循环数据 API
+
+获取在循环场景下的数据对象。举例:上层组件设置了 loop 循环数据,且设置了 `loopArgs:["item", "index"]`,当前组件的属性表达式或绑定的事件函数中,可以通过 this 上下文获取所在循环的数据环境;默认值为 `['item','index']` ,如有多层循环,需要自定义不同 loopArgs,同样通过 `this[自定义循环别名]` 获取对应的循环数据和序号;
+
+
+| 参数 | 说明 | 类型 | 可选值 |
+| ---------- | --------------------------------- | ------ | ------ |
+| this.item | 获取当前 index 对应的循环体数据; | Any | - |
+| this.index | 当前物料在循环体中的 index | Number | - |
+
+### 2.4 工具类扩展描述(AA)
+
+用于描述物料开发过程中,自定义扩展或引入的第三方工具类(例如:lodash 及 moment),增强搭建基础协议的扩展性,提供通用的工具类方法的配置方案及调用 API。
+
+| 参数 | 说明 | 类型 | 支持变量 | 默认值 |
+| ------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------- | -------- | ------ |
+| utils[] | 工具类扩展映射关系 | **UtilItem**[] | - | |
+| *UtilItem*.name | 工具类扩展项名称 | String | - | |
+| *UtilItem*.type | 工具类扩展项类型 | 枚举, `'npm'` (代表公网 npm 类型) / `'tnpm'` (代表阿里巴巴内部 npm 类型) / `'function'` (代表 Javascript 函数类型) | - | |
+| *UtilItem*.content | 工具类扩展项内容 | [ComponentMap 类型](#22-组件映射关系 a) 或 [JSFunction](#2432事件函数类型 a) | - | |
+
+描述示例:
+
+```javascript
+{
+ utils: [{
+ name: 'clone',
+ type: 'npm',
+ content: {
+ package: 'lodash',
+ version: '0.0.1',
+ exportName: 'clone',
+ subName: '',
+ destructuring: false,
+ main: '/lib/clone'
+ }
+ }, {
+ name: 'moment',
+ type: 'npm',
+ content: {
+ package: '@alifd/next',
+ version: '0.0.1',
+ exportName: 'Moment',
+ subName: '',
+ destructuring: true,
+ main: ''
+ }
+ }, {
+ name: 'recordEvent',
+ type: 'function',
+ content: {
+ type: 'JSFunction',
+ value: "function(logkey, gmkey, gokey, reqMethod) {\n goldlog.record('/xxx.event.' + logkey, gmkey, gokey, reqMethod);\n}"
+ }
+ }]
+}
+```
+
+出码结果:
+
+```javascript
+import clone from 'lodash/lib/clone';
+import { Moment } from '@alifd/next';
+
+export const recordEvent = function(logkey, gmkey, gokey, reqMethod) {
+ goldlog.record('/xxx.event.' + logkey, gmkey, gokey, reqMethod);
+}
+
+...
+```
+
+扩展的工具类,用户可以通过统一的上下文 this.utils 方法获取所有扩展的工具类或自定义函数,例如:this.utils.moment、this.utils.clone。搭建协议中的使用方式如下所示:
+
+```javascript
+{
+ componentName: 'Div',
+ props: {
+ onClick: {
+ type: 'JSFunction,
+ value: 'function(){ this.utils.clone(this.state.data); }'
+ }
+ }
+}
+```
+
+### 2.5 国际化多语言支持(AA)
+
+协议中用于描述国际化语料和组件引用国际化语料的规范,遵循集团国际化中台关于国际化语料规范定义。
+
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 |
+| ---- | -------------- | ------ | ------ | ------ |
+| i18n | 国际化语料信息 | Object | - | null |
+
+
+描述示例:
+
+```json
+{
+ "i18n": {
+ "zh-CN": {
+ "i18n-jwg27yo4": "你好",
+ "i18n-jwg27yo3": "中国"
+ },
+ "en-US": {
+ "i18n-jwg27yo4": "Hello",
+ "i18n-jwg27yo3": "China"
+ }
+ }
+}
+```
+
+使用举例:
+
+```json
+{
+ "componentName": "Button",
+ "props": {
+ "text": {
+ "type": "i18n",
+ "key": "i18n-jwg27yo4"
+ }
+ }
+}
+```
+
+```json
+{
+ "componentName": "Button",
+ "props": {
+ "text": "按钮",
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function() {\
+ console.log(this.i18n('i18n-jwg27yo4'));\
+ }"
+ }
+ }
+}
+```
+
+使用举例(已废弃)
+```json
+{
+ "componentName": "Button",
+ "props": {
+ "text": {
+ "type": "JSExpression",
+ "value": "this.i18n['i18n-jwg27yo4']"
+ }
+ }
+}
+```
+
+### 2.6 应用范围内的全局常量(AA)
+
+用于描述在整个应用内通用的全局常量,比如请求 API 的域名、环境等。
+
+### 2.7 应用范围内的全局样式(AA)
+
+用于描述在应用范围内的全局样式,比如 reset.css 等。
+
+### 2.8 当前应用配置信息(AA)
+
+用于描述当前应用的配置信息,比如当前应用的 Shell/Layout、主题等。
+
+> 注意:该字段为扩展字段,消费方式由各自场景自己决定,包括运行时和出码。
+
+### 2.9 当前应用元数据信息(AA)
+
+用于描述当前应用的元数据信息,比如当前应用的名称、Git 信息、版本号等等。
+
+> 注意:该字段为扩展字段,消费方式由各自场景自己决定,包括运行时和出码。
+
+### 2.10 当前应用的公共数据源(AA)
+
+用于描述当前应用的公共数据源,数据结构跟容器结构里的 ComponentDataSource 保持一致。
+在运行时 / 出码使用时,API 和应用级数据源 API 保持一致,都是 `this.dataSourceMap['globalDSName'].load()`
+
+### 2.11 当前应用的路由信息(AA)
+
+用于描述当前应用的路径 - 页面的关系。通过声明路由信息,应用能够在不同的路径里显示对应的页面。
+
+##### 2.11.1 Router (应用路由配置)结构描述
+
+路由配置的结构说明:
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 |
+| ----------- | ---------------------- | ------------------------------- | ------ | --------- | ------ |
+| baseName | 应用根路径 | String | - | '/' | 选填| |
+| historyMode | history 模式 | 枚举类型,包括'browser'、'hash' | - | 'browser' | 选填| |
+| routes | 路由对象组,路径与页面的关系对照组 | Route[] | - | - | 必填| |
+
+
+##### 2.11.2 Route (路由记录)结构描述
+
+路由记录,路径与页面的关系对照。Route 的结构说明:
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 |
+| -------- | ---------------------------- | ---------------------------- | ------ | ------ | ---------------------------------------------------------------------- |
+| name | 该路径项的名称 | String | - | - | 选填 |
+| path | 路径 | String | - | - | 必填,路径规则详见下面说明 |
+| query | 路径的 query 参数 | Object | - | - | 选填 |
+| page | 路径对应的页面 ID | String | - | - | 选填,page 与 redirect 字段中必须要有有一个存在 |
+| redirect | 此路径需要重定向到的路由信息 | String \| Object \| Function | - | - | 选填,page 与 redirect 字段中必须要有有一个存在,详见下文 **redirect** |
+| meta | 路由元数据 | Object | - | - | 选填 |
+| children | 子路由 | Route[] | - | - | 选填 |
+
+以上结构仅说明了路由记录需要的必需字段,如果需要更多的信息字段可以自行实现。
+
+关于 **path** 字段的详细说明:
+
+路由记录通常通过声明 path 字段来匹配对应的浏览器 URL 来确认是否满足匹配条件,如 `path=abc` 能匹配到 `/abc` 这个 URL。
+
+> 在声明 path 字段的时候,可省略 `/`,只声明后面的字符,如 `/abc` 可声明为 `abc`。
+
+path(页面路径)是浏览器URL的组成部分,同时大部分网站的 URL 也都受到了 Restful 思想的影响,所以我们也是用类似的形式作为路径的规则基底。
+路径规则是路由配置的重要组成部分,我们希望一个路径配置的基本能力需要支持具体的路径(/xxx)与路径参数 (/:abc)。
+
+以一个 `/one/:two?/three/:four?/:five?` 路径为例,它能够解析以下路径:
+- `/one/three`
+- `/one/:two/three`
+- `/one/three/:four`
+- `/one/three/:five`
+- `/one/:two/three/:four`
+- `/one/:two/three/:five`
+- `/one/three/:four/:five`
+- `/one/:two/three/:four/:five`
+
+更多的路径规则,如路径中的通配符、多次匹配等能力如有需要可自行实现。
+
+关于 **redirect** 字段的详细说明:
+
+**redirect** 字段有三种填入类型,分别是 `String`、`Object`、`Function`:
+1. 字符串(`String`)格式下默认处理为重定向到路径,支持传入 '/xxx'、'/xxx?ab=c'。
+2. 对象(`String`)格式下可传入路由对象,如 { name: 'xxx' }、{ path: '/xxx' },可重定向到对应的路由对象。
+3. 函数`Function`格式为`(to) => Route`,它的入参为当前路由项信息,支持返回一个 Route 对象或者字符串,存在一些特殊情况,在重定向的时候需要对重定向之后的路径进行处理的情况下,需要使用函数声明。
+
+```json
+{
+ "redirect": {
+ "type": "JSFunction",
+ "value": "(to) => { return { path: '/a', query: { fromPath: to.path } } }",
+ }
+}
+```
+
+##### 完整描述示例
+
+``` json
+{
+ "router": {
+ "baseName": "/",
+ "historyMode": "hash",
+ "routes": [
+ {
+ "path": "home",
+ "page": "home"
+ },
+ {
+ "path": "/*",
+ "redirect": "notFound"
+ }
+ ]
+ },
+ "componentsTree": [
+ {
+ "id": "home",
+ ...
+ },
+ {
+ "id": "notFound",
+ ...
+ }
+ ]
+}
+```
+
+### 2.12 当前应用的页面信息(AA)
+
+用于描述当前应用的页面信息,比如页面对应的低代码搭建内容、页面标题、页面配置等。
+在一些比较复杂的场景下,允许声明一层页面映射关系,以支持页面声明更多信息与配置,同时能够支持不同类型的产物。
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 |
+| ------- | --------------------- | ------ | ------ | ------ | -------------------------------------------------------- |
+| id | 页面 id | String | - | - | 必填 |
+| type | 页面类型 | String | - | - | 选填,可用来区分页面的类型 |
+| treeId | 对应的低代码树中的 id | String | - | - | 选填,页面对应的 componentsTree 中的子项 id |
+| packageId | 对应的资产包对象 | String | - | - | 选填,页面对应的资产包对象,一般用于微应用场景下,当路由匹配到当前页面的时候,会加载 `packageId` 对应的微应用进行渲染。 |
+| meta | 页面元信息 | Object | - | - | 选填,用于描述当前应用的配置信息 |
+| config | 页面配置 | Object | - | - | 选填,用于描述当前应用的元数据信息 |
+
+
+#### 2.12.1 微应用(低代码+)相关说明
+
+在开发过程中,我们经常会遇到一些特殊的情况,比如一个低代码应用想要集成一些别的系统的页面或者系统中的一些页面只能是源码开发(与低代码相对的纯工程代码形式),为了满足更多的使用场景,应用级渲染引擎引入了微应用(微前端)的概念,使低代码页面与其他的页面结合成为可能。
+
+微应用对象通过资产包加载,需要暴露两个生命周期方法:
+- mount(container: HTMLElement, props: any)
+ - 说明:微应用挂载到 container(dom 节点)的调用方法,会在渲染微应用时调用
+- unmout(container: HTMLElement, props: any)
+ - 说明:微应用从容器节点(container)卸载的调用方法,会在卸载微应用时调用
+
+> 在微应用的场景下,可能会存在多个页面路由到同一个应用,应用可通过资产包加载,所以需要将对应的页面配置指向对应的微应用(资产包)对象。
+
+**描述示例**
+
+```json
+{
+ "router": {
+ "baseName": "/",
+ "historyMode": "hash",
+ "routes": [
+ {
+ "path": "home",
+ "page": "home"
+ },
+ {
+ "page": "guide",
+ "page": "guide"
+ },
+ {
+ "path": "/*",
+ "redirect": "notFound"
+ }
+ ]
+ },
+ "pages": [
+ {
+ "id": "home",
+ "treeId": "home",
+ "meta": {
+ "title": "首页"
+ }
+ },
+ {
+ "id": "notFound",
+ "treeId": "notFound",
+ "meta": {
+ "title": "404页面"
+ }
+ },
+ {
+ "id": "guide",
+ "packagId": "microApp"
+ }
+ ]
+}
+
+// 资产包
+[
+ {
+ "id": "microApp",
+ "package": "microApp",
+ "version": "1.23.0",
+ "urls": [
+ "https://g.alicdn.com/code/lib/microApp.min.css",
+ "https://g.alicdn.com/code/lib/microApp.min.js"
+ ],
+ "library": "microApp"
+ },
+]
+```
+
+
+## 3 应用描述
+
+### 3.1 文件目录
+
+以下是推荐的应用目录结构,与标准源码 build-scripts 对齐,这里的目录结构是帮助理解应用级协议的设计,不做强约束
+
+```html
+├── META/ # 低代码元数据信息,用于多分支冲突解决、数据回滚等功能
+├── public/ # 静态文件,构建时会 copy 到 build/ 目录
+│ ├── index.html # 应用入口 HTML
+│ └── favicon.png # Favicon
+├── src/
+│ ├── components/ # 应用内的低代码业务组件
+│ │ └── guide-component/
+│ │ ├── index.js # 组件入口
+│ │ ├── components.js # 组件依赖的其他组件
+│ │ ├── schema.js # schema 描述
+│ │ └── index.scss # css 样式
+│ ├── pages/ # 页面
+│ │ └── home/ # Home 页面
+│ │ ├── index.js # 页面入口
+│ │ └── index.scss # css 样式
+│ ├── layouts/
+│ │ └── basic-layout/ # layout 组件名称
+│ │ ├── index.js # layout 入口
+│ │ ├── components.js # layout 组件依赖的其他组件
+│ │ ├── schema.js # layout schema 描述
+│ │ └── index.scss # layout css 样式
+│ ├── config/ # 配置信息
+│ │ ├── components.js # 应用上下文所有组件
+│ │ ├── routes.js # 页面路由列表
+│ │ └── app.js # 应用配置文件
+│ ├── utils/ # 工具库
+│ │ └── index.js # 应用第三方扩展函数
+│ ├── locales/ # [可选] 国际化资源
+│ │ ├── en-US
+│ │ └── zh-CN
+│ ├── global.scss # 全局样式
+│ └── index.jsx # 应用入口脚本,依赖 config/routes.js 的路由配置动态生成路由;
+├── webpack.config.js # 项目工程配置,包含插件配置及自定义 webpack 配置等
+├── README.md
+├── package.json
+├── .editorconfig
+├── .eslintignore
+├── .eslintrc.js
+├── .gitignore
+├── .stylelintignore
+└── .stylelintrc.js
+```
+
+### 3.2 应用级别 APIs
+> 下文中 `xxx` 代指任意 API
+#### 3.2.1 路由 Router API
+ - this.location.`xxx` 「不推荐,推荐统一通过 this.router api」
+ - this.history.`xxx` 「不推荐,推荐统一通过 this.router api」
+ - this.match.`xxx` 「不推荐,推荐统一通过 this.router api」
+ - this.router.`xxx`
+
+##### Router 结构说明
+
+| API | 函数签名 | 说明 |
+| -------------- | ---------------------------------------------------------- | -------------------------------------------------------------- |
+| getCurrentRoute | () => RouteLocation | 获取当前解析后的路由信息,RouteLocation 结构详见下面说明 |
+| push | (target: string \| Route) => void | 路由跳转方法,跳转到指定的路径或者 Route |
+| replace | (target: string \| Route) => void | 路由跳转方法,与 `push` 的区别在于不会增加一条历史记录而是替换当前的历史记录 |
+| beforeRouteLeave | (guard: (to: RouteLocation, from: RouteLocation) => boolean \| Route) => void | 路由跳转前的守卫方法,详见下面说明 |
+| afterRouteChange | (fn: (to: RouteLocation, from: RouteLocation) => void) => void | 路由跳转后的钩子函数,会在每次路由改变后执行 |
+
+##### 3.2.1.1 RouteLocation(路由信息)结构说明
+
+**RouteLocation** 是路由控制器匹配到对应的路由记录后进行解析产生的对象,它的结构如下:
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 | 备注 |
+| -------------- | ---------------------- | ------ | ------ | ------ | ------ |
+| path | 当前解析后的路径 | String | - | - | 必填 |
+| hash | 当前路径的 hash 值,以 # 开头 | String | - | - | 必填 |
+| href | 当前的全部路径 | String | - | - | 必填 |
+| params | 匹配到的路径参数 | Object | - | - | 必填 |
+| query | 当前的路径 query 对象 | Object | - | - | 必填,代表当前地址的 search 属性的对象 |
+| name | 匹配到的路由记录名 | String | - | - | 选填 |
+| meta | 匹配到的路由记录元数据 | Object | - | - | 选填 |
+| redirectedFrom | 原本指向向的路由记录 | Route | - | - | 选填,在重定向到当前地址之前,原先想访问的地址 |
+| fullPath | 包括 search 和 hash 在内的完整地址 | String | - | - | 选填 |
+
+
+##### beforeRouteLeave
+通过 beforeRouteLeave 注册的路由守卫方法会在每次路由跳转前执行。该方法一般会在应用鉴权,路由重定向等场景下使用。
+
+> `beforeRouteLeave` 只在 `router.push/replace` 的方法调用时生效。
+
+传入守卫的入参为:
+* to: 即将要进入的目标路由(RouteLocation)
+* from: 当前导航正要离开的路由(RouteLocation)
+
+该守卫返回一个 `boolean` 或者路由对象来告知路由控制器接下来的行为。
+* 如果返回 `false`, 则停止跳转
+* 如果返回 `true`,则继续跳转
+* 如果返回路由对象,则重定向至对应的路由
+
+**使用范例:**
+
+```json
+{
+ "componentsTree": [{
+ "componentName": "Page",
+ "fileName": "Page1",
+ "props": {},
+ "children": [{
+ "componentName": "Div",
+ "props": {},
+ "children": [{
+ "componentName": "Button",
+ "props": {
+ "text": "跳转到首页",
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function () { this.router.push('/home'); }"
+ }
+ },
+ }]
+ }],
+ }]
+}
+```
+
+
+#### 3.2.2 应用级别的公共函数或第三方扩展
+ - this.utils.`xxx`
+
+#### 3.2.3 国际化相关 API
+| API | 函数签名 | 说明 |
+| -------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------ |
+| this.i18n | (i18nKey: string, params?: { [paramName: string]: string; }) => string | i18nKey 是语料的标识符,params 可选,是用来做模版字符串替换的。返回语料字符串 |
+| this.getLocale | () => string | 返回当前环境语言 code |
+| this.setLocale | (locale: string) => void | 设置当前环境语言 code |
+
+**使用范例:**
+```json
+{
+ "componentsTree": [{
+ "componentName": "Page",
+ "fileName": "Page1",
+ "props": {},
+ "children": [{
+ "componentName": "Div",
+ "props": {},
+ "children": [{
+ "componentName": "Button",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.i18n('i18n-hello')"
+ },
+ "onClick": {
+ "type": "JSFunction",
+ "value": "function () { this.setLocale('en-US'); }"
+ }
+ },
+ }, {
+ "componentName": "Button",
+ "props": {
+ "children": {
+ "type": "JSExpression",
+ "value": "this.i18n('i18n-chicken', { count: this.state.count })"
+ },
+ },
+ }]
+ }],
+ }],
+ "i18n": {
+ "zh-CN": {
+ "i18n-hello": "你好",
+ "i18n-chicken": "我有{count}只鸡"
+ },
+ "en-US": {
+ "i18n-hello": "Hello",
+ "i18n-chicken": "I have {count} chicken"
+ }
+ }
+}
+```
diff --git a/docs/docs/specs/material-spec.md b/docs/docs/specs/material-spec.md
new file mode 100644
index 0000000000..c766c68347
--- /dev/null
+++ b/docs/docs/specs/material-spec.md
@@ -0,0 +1,1671 @@
+---
+title: 《低代码引擎物料协议规范》
+sidebar_position: 1
+---
+
+## 1 介绍
+
+### 1.1 本协议规范涉及的问题域
+
+- 定义本协议版本号规范
+- 定义本协议中每个子规范需要被支持的 Level
+- 定义中后台物料目录规范(A)
+- 定义中后台物料 API 规范(A)
+- 定义中后台物料入库规范(A)
+- 定义中后台物料国际化多语言支持规范(AA)
+- 定义中后台物料主题配置规范(AAA)
+- 定义中后台物料无障碍访问规范(AAA)
+
+
+### 1.2 协议草案起草人
+
+- 撰写:九神、大果、元彦、戊子、林熠、屹凡、金禅
+- 审阅:潕量、月飞、康为、力皓、荣彬、暁仙、度城、金禅、戊子、林熠、絮黎
+
+### 1.3 版本号
+
+1.0.0
+
+### 1.4 协议版本号规范(A)
+
+本协议采用语义版本号,版本号格式为 `major.minor.patch` 的形式。
+
+- major 是大版本号:用于发布不向下兼容的协议格式修改
+- minor 是小版本号:用于发布向下兼容的协议功能新增
+- patch 是补丁号:用于发布向下兼容的协议问题修正
+
+
+### 1.5 协议中子规范 Level 定义
+
+| 规范等级 | 实现要求 |
+| -------- | ---------------------------------------------------------------------------------- |
+| A | 强制规范,必须实现;违反此类规范的协议描述数据将无法写入物料中心,不支持流通。 |
+| AA | 推荐规范,推荐实现;遵守此类规范有助于业务未来的扩展性和跨团队合作研发效率的提升。 |
+| AAA | 参考规范,根据业务场景实际诉求实现;是集团层面鼓励的技术实现引导。 |
+
+
+### 1.6 名词术语
+- **物料**:能够被沉淀下来直接使用的前端能力,一般表现为业务组件、区块、模板。
+- **业务组件(Business Component)**:业务领域内基于基础组件之上定义的组件,可能会包含特定业务域的交互或者是业务数据,对外仅暴露可配置的属性,且必须发布到公域(如阿里 NPM);在同一个业务域内可以流通,但不需要确保可以跨业务域复用。
+ - **低代码业务组件(Low-Code Business Component)**:通过低代码编辑器搭建而来,有别于源码开发的业务组件,属于业务组件中的一种类型,遵循业务组件的定义;同时低代码业务组件还可以通过低代码编辑器继续多次编辑。
+- **区块(Block)**:通过低代码搭建的方式,将一系列业务组件、布局组件进行嵌套组合而成,不对外提供可配置的属性。可通过区块容器组件的包裹,实现区块内部具备有完整的样式、事件、生命周期管理、状态管理、数据流转机制。能独立存在和运行,可通过复制 schema 实现跨页面、跨应用的快速复用,保障功能和数据的正常。
+- **模板(Template)**:特定垂直业务领域内的业务组件、区块可组合为单个页面,或者是再配合路由组合为多个页面集,统称为模板。
+
+### 1.7 物料规范背景
+目前集团业务融合频繁,而物料规范的不统一给业务融合带来额外的高成本,另一方面集团各个 BU 的前端物料也存在不同程度的重复建设。我们期望通过集团层面的物料通不阻碍业务融合的发展,同时通过集团层面的物料流通来提升物料丰富度,通过丰富物料的复用来提效中后台系统研发,同时也能给新业务场景提供高质量的启动物料。
+
+### 1.8 物料规范定义
+
+- **源码物料规范**:一套面向开发者的目录规范,用于规范化约束开发过程中的代码、文档、接口规范,以方便物料在集团内的流通。
+- **搭建物料规范**:一套面向开发者的 Schema 规范,用于规范化约束开发过程中的代码、文档、接口规范,以方便物料在集团内的流通。
+
+## 2. 物料规范 - 业务组件规范
+
+### 2.1 源码规范
+
+#### 2.1.1 目录规范(A)
+
+
+```
+component // 组件名称, 比如 biz-button
+ ├── build // 【编译生成】【必选】
+ │ └── index.html // 【编译生成】【必选】可直接预览文件
+ ├── lib // 【编译生成】【必选】
+ │ ├── index.js // 【编译生成】【必选】js 入口文件
+ │ ├── index.scss // 【编译生成】【必选】css 入口文件
+ │ └── style.js // 【编译生成】【必选】js 版本 css 入口文件,方便去重
+ ├── demo // 【必选】组件文档目录,可以有多个 md 文件
+ │ └── basic.md // 【必选】组件文档示例,用于生成组件开发预览,以及生成组件文档
+ ├── src // 【必选】组件源码
+ │ ├── index.js // 【必选】组件出口文件
+ │ └── index.scss // 【必选】仅包含组件自身样式的源码文件
+ ├── README.md // 【必选】组件说明及 API
+ └── package.json // 【必选】组件 package.json
+```
+
+
+##### README.md
+
+- README.md 应该包含业务组件的源信息、使用说明以及 API,示例如下:
+
+```
+# 按钮 // 这一行是标题
+
+按钮用于开始一个即时操作。 // 这一行是描述
+
+{这段通过工程能力自动注入, 开发者无需编写
+## 安装方法
+npm install @alifd/ice-layout -S
+}
+
+## API
+
+| 参数 | 说明 | 类型 | 可选值 | 默认值 |
+| ---- | ---- | ------ | ------------------- | ------ |
+| type | 类型 | String | `primary`、`normal` | `normal` |
+```
+
+
+
+- README.en-US.md(文件命名采取 [bcp47 规范](http://www.rfc-editor.org/rfc/bcp/bcp47.txt))多语言的情况,可选
+
+```
+# Button
+
+Button use to trigger an action.
+
+{这段通过工程能力自动注入, 开发者无需编写
+## Install
+npm install @alifd/ice-layout -S
+}
+
+## API
+
+| Param | Description | Type | Enum | Default |
+| ----- | ----------- | ------ | ------------------- | ------- |
+| type | type | String | `primray`、`normal` | normal |
+```
+
+##### package.json
+`package.json` 中包含了一些依赖信息和配置信息,示例如下:
+
+```json
+{
+ "name": "@alife/1688-button",
+ "description": "业务组件描述",
+ "version": "0.0.1",
+ "main": "lib/index.js",
+ "stylePath": "lib/style.js", // 【私有字段】样式文件地址,webpack 插件引用
+ "files": [
+ "demo/",
+ "lib/",
+ "build/" // 存放编译后的 demo,发布前应该编译生成该目录
+ ],
+ "dependencies": {
+ "@alifd/next": "1.x" // 【可选】可以是一个 util 类型的组件,如果依赖 next,请务必写语义化版本号,不要写*这种
+ },
+ "devDependencies": {
+ "react": "^16.5.0",
+ "react-dom": "^16.5.0"
+ },
+ "peerDependencies": {
+ "react": "^16.5.0"
+ },
+ "componentConfig": { // 【私有字段】组件配置信息
+ "name": "button", // 组件英文名
+ "title": "按钮", // 组件中文名
+ "category": "form" // 组件分类
+ }
+}
+```
+
+##### src/index.js
+
+包含组件的出口文件,示例如下:
+
+```javascript
+import Button from './Button.jsx';
+import ButtonGroup from './ButtonGroup.jsx';
+
+export const Group = ButtonGroup; // 子组件推荐写法
+
+export default Button;
+```
+
+推荐用法
+
+```javascript
+import Button, { Group } form '@scope/button';
+```
+
+##### src/index.scss
+
+```css
+/* 不引入依赖组件的样式,比如组件 import { Button } from '@alifd/next'; */
+/* 不需要在 index.scss 中引入 @import '~@alifd/next/lib/button/index.scss'; */
+
+/* 如果需要引入主题变量引入此段 */
+@import '~@alifd/next/variables.scss';
+
+/* 组件自身样式 */
+.custom-component {
+ color: $color-brand1-1;
+}
+```
+
+##### demo
+demo 目录存放的是组件的文档,无文档的业务组件无法带来任何价值,因此 demo 是必选项。demo 目录下的文件采取 markdown 的写法,可以是多个文件,示例(demo/basic.md)如下:
+
+demo/basic.md
+
+~~~
+---
+title: {按钮类型}
+order: {文档的排序,数字,0 最小,从小到大排序}
+---
+
+按钮有三种视觉层次:主按钮、次按钮、普通按钮。不同的类型可以用来区别按钮的重要程度。
+
+:::lang=en-US
+---
+title: Container
+order: 3
+---
+
+Change the default container by passing a function to `container`;
+enable `useAbsolute` to use `absolute position` to implement affix component;
+
+:::
+
+```jsx // 以下建议用英文编写
+import Button from '@alife/1688-button';
+
+ReactDOM.render(
+
+
, mountNode);
+```
+
+```css
+.test {
+ background: #CCC;
+}
+```
+~~~
+
+#### 2.1.2 API 规范(A)
+
+API 是组件的属性解释,给开发者作为组件属性配置的参考。为了保持 API 的一致性,我们制定这个 API 命名规范。对于业界通用的,约定俗成的命名,我们遵循社区的约定。对于业界有多种规则难以确定的,我们确定其中一种,大家共同遵守。
+
+##### 通用规则
+
+- 所有的 API 采用小驼峰的书写规则,如 `onChange`、`direction`、`defaultVisible`。
+- 标签名采用大驼峰书写规则,如 `Menu`、`Slider`、`DatePicker`。
+
+##### 通用命名
+
+| API 名称 | 类型 | 描述 | 常见变量 |
+| :------------- | :------------- | :----------------------------------------------------------- | :---------------------------------------------------- |
+| shape | string | 形状,从组件的外形来看有区别的时候,使用 shape | |
+| direction | enum | 方向,取值采用缩写的方式。 | hoz(水平), ver(垂直) |
+| align | enum | 对齐方式 | tl, tc, tr, cl, cc, cr, bl, bc, br |
+| status | enum | 状态 | normal, success, error, warning |
+| size | enum | 大小 | small, medium, large 更大或更小可用 (xxs, xs, xl, xxl) |
+| type | enum or string | 分类:1. dom 结构不变、只有皮肤的变化 2.组件类型只有并列的几类 | normal, primary, secondary |
+| visible | boolean | 是否显示 | |
+| defaultVisible | boolean | 是否显示(非受控) | |
+| disabled | boolean | 禁用组件 | |
+| closable | bool/string | 允许关闭的方式 | |
+| htmlType | string | 当原生组件与 Fusion 组件的 type 产生冲突时,原生组件使用 `htmlType` | |
+| link | string | 链接 | |
+| dataSource | array | 列表数据源 | [{label, value}, {label, value}] |
+| has+'属性' | boolean | 拥有某个属性 | 例如 `hasArrow`, `hasHeader`, `hasClose` 等等 |
+
+
+##### 多选枚举
+
+当某个 API 的接口,允许用户指定多个枚举值的时候,我们把这个接口定义为多选枚举。一个很典型的例子是某个弹层组件的 `closable` 属性,我们会允许:键盘 esc 按键、点击 mask、点击 close 按钮、点击组件以外的任何区域进行关闭。
+
+不要有一个 API 值,支持多种类型。例如某个弹层的组件,我们会允许 esc、点击 mask、点击 close 按钮等进行关闭。此时 API 设计可以通过多个 API 承载,例如:
+
+```js
+closable?: boolean; // 默认为 true
+closeMode?: CM[] | string; // 默认值是 ['close', 'mask', 'esc']
+```
+
+true 表示触发规则都会关闭,false 表示触发规则不会关闭。
+
+示例:
+
+- ``,所有合法条件都会关闭
+- ``,任何情况下都不关闭,只能通过受控设置 visible
+- ``,用户按 esc 或者点击关闭按钮会关闭
+
+##### 事件
+
+- 标准事件或者自定义的符合 w3c 标准的事件,命名必须 on 开头, 即 `on` + 事件名,如 onExpand。
+
+##### 表单规范
+
+- 支持[受控模式](https://reactjs.org/docs/forms.html#controlled-components)(value + onChange) (A)
+ - value 控制组件数据展现
+ - onChange 组件发生变化时候的回调函数(第一个参数可以给到 value)
+- `value={undefined}`的时候清空数据,field 的 reset 函数会给所有组件下发 undefined 数据 (AA))
+- 一次完整操作抛一次 onChange 事件 `建议` 比如有 Process 表示进展中的状态,建议增加 API `onProcess`;如果有 Start 表示启动状态,建议增加 API `onStart` (AA)
+
+##### 属性的传递
+**1. 原子组件(Atomic Component)**
+> 最小粒子,不能再拆分的组件
+
+举例:Input/Button/NumberPicker
+
+期望使用起来像普通的 html 标签一样,能够把用户传入的参数,透传到真正的节点上。
+
+```jsx
+
+```
+
+渲染后的 dom 结构:
+
+```jsx
+
+
+
+```
+
+**2. 复合组件(Composite component)**
+
+复合组件一般由两个及以上的原子组件/复合组件构成,比如:Select 由 Inupt + 弹窗组成,Search 由 Select + Button 组成,TreeSelect 由 Tree + Select 组成。
+
+为了提高组件使用的便利性,对 API 属性的要求如下:
+1. 复合组件核心的原子组件(比如 Search 的核心原子组件是 Input)的属性以及使用频率高的属性建议扁平化,让复合组件可以直接使用其属性;
+2. 复合组件内的非核心原子组件,则通过 `xxxProps` (如 inputProps/btnProps)的方式,将参数传递到相应原子组件上。
+
+
+**属性扁平化例子**:
+
+比如 `Search` 组件由 `Input` 和 `Button` 构成,但是 `Search` 更像是 `Input` ,因此把 `Input` 作为主要组件,将属性扁平化。即在 `Search` 组件上直接使用一些 `Input` 的属性。 ``
+
+比如 `Select` `TreeSelect` 都有弹层部分,`Overlay` `Overlay.Popup` 的 `visible` 属性使用率较高,一般用于 fixed 布局下的弹窗滚动跟随。因此把该属性暴露到最外层,简化使用 `