Repository: alibaba/lowcode-engine
Branch: main
Commit: f6305c228495
Files: 2530
Total size: 5.4 MB
Directory structure:
gitextract_4erw24n6/
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ └── bug-report.md
│ └── workflows/
│ ├── check base branch.yml
│ ├── ci.yml
│ ├── cov packages.yml
│ ├── help wanted.yml
│ ├── insufficient information.yml
│ ├── pr comment by chatgpt.yml
│ ├── pre build.yml
│ ├── publish docs.yml
│ ├── publish engine beta.yml
│ ├── publish engine.yml
│ ├── stale.yml
│ ├── test modules.yml
│ └── test packages.yml
├── .gitignore
├── .prettierrc.js
├── .stylelintignore
├── .stylelintrc.js
├── CONTRIBUTOR.md
├── LICENSE
├── abc.json
├── babel.config.js
├── commitlint.config.js
├── deploy-space/
│ ├── lerna.json
│ ├── package.json
│ ├── static/
│ │ ├── index.html
│ │ └── preview.html
│ └── tsconfig.json
├── docs/
│ ├── .gitignore
│ ├── README.md
│ ├── babel.config.js
│ ├── community/
│ │ └── issue.md
│ ├── config/
│ │ ├── navbar.js
│ │ ├── sidebars.js
│ │ └── sidebarsCommunity.js
│ ├── docs/
│ │ ├── api/
│ │ │ ├── canvas.md
│ │ │ ├── command.md
│ │ │ ├── common.md
│ │ │ ├── commonUI.md
│ │ │ ├── config.md
│ │ │ ├── configOptions.md
│ │ │ ├── event.md
│ │ │ ├── hotkey.md
│ │ │ ├── index.md
│ │ │ ├── init.md
│ │ │ ├── logger.md
│ │ │ ├── material.md
│ │ │ ├── model/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── clipboard.md
│ │ │ │ ├── component-meta.md
│ │ │ │ ├── detecting.md
│ │ │ │ ├── document-model.md
│ │ │ │ ├── dragon.md
│ │ │ │ ├── drop-location.md
│ │ │ │ ├── editor-view.md
│ │ │ │ ├── history.md
│ │ │ │ ├── modal-nodes-manager.md
│ │ │ │ ├── node-children.md
│ │ │ │ ├── node.md
│ │ │ │ ├── plugin-instance.md
│ │ │ │ ├── prop.md
│ │ │ │ ├── props.md
│ │ │ │ ├── resource.md
│ │ │ │ ├── selection.md
│ │ │ │ ├── setting-field.md
│ │ │ │ ├── setting-top-entry.md
│ │ │ │ ├── simulatorRender.md
│ │ │ │ └── window.md
│ │ │ ├── plugins.md
│ │ │ ├── project.md
│ │ │ ├── setters.md
│ │ │ ├── simulatorHost.md
│ │ │ ├── skeleton.md
│ │ │ └── workspace.md
│ │ ├── article/
│ │ │ └── index.md
│ │ ├── demoUsage/
│ │ │ ├── advanced/
│ │ │ │ ├── _category_.json
│ │ │ │ └── hotkey.md
│ │ │ ├── appendix/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── api.md
│ │ │ │ └── loop.md
│ │ │ ├── intro.md
│ │ │ ├── makeStuff/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── dialog.md
│ │ │ │ └── table.md
│ │ │ └── panels/
│ │ │ ├── _category_.json
│ │ │ ├── canvas.md
│ │ │ ├── code.md
│ │ │ ├── component.md
│ │ │ ├── datasource.md
│ │ │ └── settings.md
│ │ ├── faq/
│ │ │ ├── faq001.md
│ │ │ ├── faq002.md
│ │ │ ├── faq003.md
│ │ │ ├── faq004.md
│ │ │ ├── faq005.md
│ │ │ ├── faq006.md
│ │ │ ├── faq007.md
│ │ │ ├── faq008.md
│ │ │ ├── faq009.md
│ │ │ ├── faq010.md
│ │ │ ├── faq011.md
│ │ │ ├── faq012.md
│ │ │ ├── faq013.md
│ │ │ ├── faq014.md
│ │ │ ├── faq015.md
│ │ │ ├── faq016.md
│ │ │ ├── faq017.md
│ │ │ ├── faq018.md
│ │ │ ├── faq019.md
│ │ │ ├── faq020.md
│ │ │ ├── faq021.md
│ │ │ ├── faq022.md
│ │ │ ├── faq023.md
│ │ │ ├── faq024.md
│ │ │ └── index.md
│ │ ├── guide/
│ │ │ ├── appendix/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── glossary.md
│ │ │ │ ├── metaSpec.md
│ │ │ │ ├── npms.md
│ │ │ │ ├── repos.md
│ │ │ │ ├── setterDetails/
│ │ │ │ │ ├── _category_.json
│ │ │ │ │ ├── array.md
│ │ │ │ │ ├── behavior.md
│ │ │ │ │ ├── bool.md
│ │ │ │ │ ├── color.md
│ │ │ │ │ ├── event.md
│ │ │ │ │ ├── function.md
│ │ │ │ │ ├── icon.md
│ │ │ │ │ ├── mixed.md
│ │ │ │ │ ├── number.md
│ │ │ │ │ ├── radioGroup.md
│ │ │ │ │ ├── select.md
│ │ │ │ │ ├── slot.md
│ │ │ │ │ ├── string.md
│ │ │ │ │ ├── style.md
│ │ │ │ │ ├── textArea.md
│ │ │ │ │ └── variable.md
│ │ │ │ └── setters.md
│ │ │ ├── create/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── useEditor.md
│ │ │ │ └── useRenderer.md
│ │ │ ├── design/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── datasourceEngine.md
│ │ │ │ ├── editor.md
│ │ │ │ ├── generator.md
│ │ │ │ ├── materialParser.md
│ │ │ │ ├── renderer.md
│ │ │ │ ├── setter.md
│ │ │ │ ├── specs.md
│ │ │ │ └── summary.md
│ │ │ ├── expand/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── editor/
│ │ │ │ │ ├── _category_.json
│ │ │ │ │ ├── cli.md
│ │ │ │ │ ├── graph.md
│ │ │ │ │ ├── material.md
│ │ │ │ │ ├── metaSpec.md
│ │ │ │ │ ├── parts/
│ │ │ │ │ │ ├── _category_.json
│ │ │ │ │ │ ├── partsIntro.md
│ │ │ │ │ │ ├── partsassets.md
│ │ │ │ │ │ ├── partslcc.md
│ │ │ │ │ │ └── prototype.md
│ │ │ │ │ ├── pluginContextMenu.md
│ │ │ │ │ ├── pluginWidget.md
│ │ │ │ │ ├── setter.md
│ │ │ │ │ ├── summary.md
│ │ │ │ │ └── theme.md
│ │ │ │ └── runtime/
│ │ │ │ ├── _category_.json
│ │ │ │ ├── codeGeneration.md
│ │ │ │ └── renderer.md
│ │ │ └── quickStart/
│ │ │ ├── _category_.json
│ │ │ ├── demo.md
│ │ │ ├── intro.md
│ │ │ └── start.md
│ │ ├── participate/
│ │ │ ├── code-specification.md
│ │ │ ├── flow.md
│ │ │ ├── index.md
│ │ │ └── meet.md
│ │ ├── specs/
│ │ │ ├── assets-spec.md
│ │ │ ├── lowcode-spec.md
│ │ │ └── material-spec.md
│ │ └── video/
│ │ └── index.md
│ ├── docusaurus.config.js
│ ├── package.json
│ ├── scripts/
│ │ ├── getDocsFromDir.js
│ │ └── sync-oss.js
│ ├── src/
│ │ ├── css/
│ │ │ └── custom.css
│ │ └── pages/
│ │ ├── index-old.tsx
│ │ ├── index.module.css
│ │ ├── index.tsx
│ │ └── markdown-page.md
│ └── tsconfig.json
├── index.ts
├── lerna.json
├── modules/
│ ├── code-generator/
│ │ ├── .gitignore
│ │ ├── .prettierrc.js
│ │ ├── .versionrc
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── README.md
│ │ ├── babel.config.js
│ │ ├── bin/
│ │ │ └── lowcode-code-generator.js
│ │ ├── example-schema.json
│ │ ├── example-schema.json5
│ │ ├── jest.config.js
│ │ ├── jest.setup.js
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ ├── build-cli.js
│ │ │ ├── build-standalone-loader.js
│ │ │ ├── build-standalone-worker.js
│ │ │ ├── build-standalone.js
│ │ │ ├── build-template-static-files.js
│ │ │ ├── build-types
│ │ │ ├── build.js
│ │ │ ├── move-files-to-build-dest.js
│ │ │ ├── run-demo-project
│ │ │ └── test-standalone.js
│ │ ├── src/
│ │ │ ├── analyzer/
│ │ │ │ └── componentAnalyzer.ts
│ │ │ ├── cli/
│ │ │ │ ├── index.ts
│ │ │ │ ├── init-solution.ts
│ │ │ │ ├── run.ts
│ │ │ │ └── solutions/
│ │ │ │ └── example-solution.ts
│ │ │ ├── config/
│ │ │ │ └── env.ts
│ │ │ ├── const/
│ │ │ │ ├── file.ts
│ │ │ │ ├── generator.ts
│ │ │ │ └── index.ts
│ │ │ ├── core/
│ │ │ │ └── jsx/
│ │ │ │ ├── handlers/
│ │ │ │ │ ├── transformJsExpression.ts
│ │ │ │ │ └── transformThis2Context.ts
│ │ │ │ └── util/
│ │ │ │ ├── isLiteralAtomicExpr.ts
│ │ │ │ └── isSimpleStraightLiteral.ts
│ │ │ ├── generator/
│ │ │ │ ├── ChunkBuilder.ts
│ │ │ │ ├── CodeBuilder.ts
│ │ │ │ ├── ModuleBuilder.ts
│ │ │ │ └── ProjectBuilder.ts
│ │ │ ├── index.ts
│ │ │ ├── parser/
│ │ │ │ └── SchemaParser.ts
│ │ │ ├── plugins/
│ │ │ │ ├── common/
│ │ │ │ │ ├── esmodule.ts
│ │ │ │ │ ├── requireUtils.ts
│ │ │ │ │ └── styleImport.ts
│ │ │ │ ├── component/
│ │ │ │ │ ├── rax/
│ │ │ │ │ │ ├── commonDeps.ts
│ │ │ │ │ │ ├── const.ts
│ │ │ │ │ │ ├── containerClass.ts
│ │ │ │ │ │ ├── containerInitState.ts
│ │ │ │ │ │ ├── containerInjectContext.ts
│ │ │ │ │ │ ├── containerInjectDataSourceEngine.ts
│ │ │ │ │ │ ├── containerInjectUtils.ts
│ │ │ │ │ │ ├── containerLifeCycle.ts
│ │ │ │ │ │ ├── containerMethods.ts
│ │ │ │ │ │ └── jsx.ts
│ │ │ │ │ ├── react/
│ │ │ │ │ │ ├── const.ts
│ │ │ │ │ │ ├── containerClass.ts
│ │ │ │ │ │ ├── containerInitState.ts
│ │ │ │ │ │ ├── containerInjectConstants.ts
│ │ │ │ │ │ ├── containerInjectContext.ts
│ │ │ │ │ │ ├── containerInjectDataSourceEngine.ts
│ │ │ │ │ │ ├── containerInjectI18n.ts
│ │ │ │ │ │ ├── containerInjectUtils.ts
│ │ │ │ │ │ ├── containerLifeCycle.ts
│ │ │ │ │ │ ├── containerMethod.ts
│ │ │ │ │ │ ├── jsx.ts
│ │ │ │ │ │ └── reactCommonDeps.ts
│ │ │ │ │ └── style/
│ │ │ │ │ └── css.ts
│ │ │ │ └── project/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── framework/
│ │ │ │ │ ├── icejs/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── plugins/
│ │ │ │ │ │ │ ├── entry.ts
│ │ │ │ │ │ │ ├── entryHtml.ts
│ │ │ │ │ │ │ ├── globalStyle.ts
│ │ │ │ │ │ │ ├── packageJSON.ts
│ │ │ │ │ │ │ └── router.ts
│ │ │ │ │ │ └── template/
│ │ │ │ │ │ ├── files/
│ │ │ │ │ │ │ ├── README.md.ts
│ │ │ │ │ │ │ ├── abc.json.ts
│ │ │ │ │ │ │ ├── build.json.ts
│ │ │ │ │ │ │ ├── editorconfig.ts
│ │ │ │ │ │ │ ├── eslintignore.ts
│ │ │ │ │ │ │ ├── eslintrc.js.ts
│ │ │ │ │ │ │ ├── gitignore.ts
│ │ │ │ │ │ │ ├── jsconfig.json.ts
│ │ │ │ │ │ │ ├── prettierignore.ts
│ │ │ │ │ │ │ ├── prettierrc.js.ts
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ └── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx.ts
│ │ │ │ │ │ │ │ │ │ └── index.style.ts
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx.ts
│ │ │ │ │ │ │ │ │ │ └── index.style.ts
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx.ts
│ │ │ │ │ │ │ │ ├── index.jsx.ts
│ │ │ │ │ │ │ │ └── menuConfig.js.ts
│ │ │ │ │ │ │ ├── stylelintignore.ts
│ │ │ │ │ │ │ ├── stylelintrc.js.ts
│ │ │ │ │ │ │ └── tsconfig.json.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── static-files.ts
│ │ │ │ │ ├── icejs3/
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── plugins/
│ │ │ │ │ │ │ ├── appConfig.ts
│ │ │ │ │ │ │ ├── buildConfig.ts
│ │ │ │ │ │ │ ├── globalStyle.ts
│ │ │ │ │ │ │ ├── layout.ts
│ │ │ │ │ │ │ └── packageJSON.ts
│ │ │ │ │ │ └── template/
│ │ │ │ │ │ ├── files/
│ │ │ │ │ │ │ ├── README.md.ts
│ │ │ │ │ │ │ ├── browserslistrc.ts
│ │ │ │ │ │ │ ├── document.ts
│ │ │ │ │ │ │ ├── gitignore.ts
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ └── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx.ts
│ │ │ │ │ │ │ │ │ │ └── index.style.ts
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx.ts
│ │ │ │ │ │ │ │ │ │ └── index.style.ts
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx.ts
│ │ │ │ │ │ │ │ ├── index.jsx.ts
│ │ │ │ │ │ │ │ └── menuConfig.js.ts
│ │ │ │ │ │ │ ├── tsconfig.ts
│ │ │ │ │ │ │ └── typings.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── static-files.ts
│ │ │ │ │ └── rax/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── plugins/
│ │ │ │ │ │ ├── appConfig.ts
│ │ │ │ │ │ ├── buildConfig.ts
│ │ │ │ │ │ ├── entry.ts
│ │ │ │ │ │ ├── entryDocument.ts
│ │ │ │ │ │ ├── globalStyle.ts
│ │ │ │ │ │ └── packageJSON.ts
│ │ │ │ │ ├── template/
│ │ │ │ │ │ ├── files/
│ │ │ │ │ │ │ ├── .eslintignore.ts
│ │ │ │ │ │ │ ├── .eslintrc.js.ts
│ │ │ │ │ │ │ ├── .gitignore.ts
│ │ │ │ │ │ │ ├── .prettierignore.ts
│ │ │ │ │ │ │ ├── .prettierrc.js.ts
│ │ │ │ │ │ │ ├── .stylelintignore.ts
│ │ │ │ │ │ │ ├── .stylelintrc.js.ts
│ │ │ │ │ │ │ ├── README.md.ts
│ │ │ │ │ │ │ ├── jsconfig.json.ts
│ │ │ │ │ │ │ └── tsconfig.json.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── static-files.ts
│ │ │ │ │ └── types/
│ │ │ │ │ └── RaxFrameworkOptions.ts
│ │ │ │ ├── i18n.ts
│ │ │ │ └── utils.ts
│ │ │ ├── polyfills/
│ │ │ │ └── buffer.ts
│ │ │ ├── postprocessor/
│ │ │ │ ├── index.ts
│ │ │ │ └── prettier/
│ │ │ │ └── index.ts
│ │ │ ├── publisher/
│ │ │ │ ├── disk/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ └── zip/
│ │ │ │ ├── index.ts
│ │ │ │ └── utils.ts
│ │ │ ├── solutions/
│ │ │ │ ├── icejs.ts
│ │ │ │ ├── icejs3.ts
│ │ │ │ └── rax-app.ts
│ │ │ ├── standalone-loader.ts
│ │ │ ├── standalone-worker.ts
│ │ │ ├── standalone.ts
│ │ │ ├── types/
│ │ │ │ ├── analyze.ts
│ │ │ │ ├── core.ts
│ │ │ │ ├── deps.ts
│ │ │ │ ├── error.ts
│ │ │ │ ├── file.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── intermediate.ts
│ │ │ │ ├── jsx.ts
│ │ │ │ └── publisher.ts
│ │ │ ├── typings.d.ts
│ │ │ └── utils/
│ │ │ ├── OrderedSet.ts
│ │ │ ├── Scope.ts
│ │ │ ├── ScopeBindings.ts
│ │ │ ├── aopHelper.ts
│ │ │ ├── common.ts
│ │ │ ├── compositeType.ts
│ │ │ ├── dataSource.ts
│ │ │ ├── debug.ts
│ │ │ ├── encodeJsxAttrString.ts
│ │ │ ├── errors.ts
│ │ │ ├── expressionParser.ts
│ │ │ ├── format.ts
│ │ │ ├── index.ts
│ │ │ ├── jsExpression.ts
│ │ │ ├── jsSlot.ts
│ │ │ ├── jsxHelpers.ts
│ │ │ ├── nodeToJSX.ts
│ │ │ ├── pathHelper.ts
│ │ │ ├── resultHelper.ts
│ │ │ ├── schema.ts
│ │ │ ├── templateHelper.ts
│ │ │ ├── theme.ts
│ │ │ ├── validate.ts
│ │ │ └── version.ts
│ │ ├── standalone/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── standalone-loader/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── standalone-worker/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── static-files/
│ │ │ └── rax/
│ │ │ ├── .eslintignore.template
│ │ │ ├── .eslintrc.js.template
│ │ │ ├── .gitignore.template
│ │ │ ├── .prettierignore.template
│ │ │ ├── .prettierrc.js.template
│ │ │ ├── .stylelintignore.template
│ │ │ ├── .stylelintrc.js.template
│ │ │ ├── README.md.template
│ │ │ ├── jsconfig.json.template
│ │ │ └── tsconfig.json.template
│ │ ├── tests/
│ │ │ ├── bugfix/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── i18n-with-params.schema.json
│ │ │ │ ├── i18n-with-params.test.ts
│ │ │ │ ├── icejs-import-wrong-naming.schema.json
│ │ │ │ ├── icejs-import-wrong-naming.test.ts
│ │ │ │ ├── icejs-js-function1.schema.json
│ │ │ │ ├── icejs-js-function1.test.ts
│ │ │ │ ├── icejs-missing-imports-1.schema.json
│ │ │ │ ├── icejs-missing-imports-1.test.ts
│ │ │ │ ├── icejs-package-json-dependencies.schema.json
│ │ │ │ ├── icejs-package-json-dependencies.test.ts
│ │ │ │ ├── icejs-page-map1.schema.json
│ │ │ │ ├── icejs-page-map1.test.ts
│ │ │ │ ├── page-element1.schema.json
│ │ │ │ ├── page-element1.test.ts
│ │ │ │ ├── page-element2.schema.json
│ │ │ │ ├── page-element2.test.ts
│ │ │ │ ├── strict-mode-context-1.schema.json
│ │ │ │ ├── strict-mode-context-1.test.ts
│ │ │ │ ├── tolerate-eval-errors-1-loop.schema.json
│ │ │ │ ├── tolerate-eval-errors-1-loop.test.ts
│ │ │ │ ├── tolerate-eval-errors-2-nested-loop.schema.json
│ │ │ │ └── tolerate-eval-errors-2-nested-loop.test.ts
│ │ │ ├── cli.test.ts
│ │ │ ├── fixtures/
│ │ │ │ └── test-cases/
│ │ │ │ ├── .gitignore
│ │ │ │ ├── icejs3-app/
│ │ │ │ │ ├── demo1/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo2/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo2-utils-name-alias/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Aaaa/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo3/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo4/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo5/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo6-literal-condition/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo7-literal-condition2/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo8-datasource-prop/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Example/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo9-datasource-engine/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── $/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo_10-jsslot/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ └── src/
│ │ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ └── demo_11-jsslot-2/
│ │ │ │ │ ├── expected/
│ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ ├── .browserslistrc
│ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ ├── ice.config.mts
│ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ └── src/
│ │ │ │ │ │ ├── app.ts
│ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ ├── document.tsx
│ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ ├── Test/
│ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ └── layout.jsx
│ │ │ │ │ │ ├── typings.d.ts
│ │ │ │ │ │ └── utils.js
│ │ │ │ │ └── schema.json5
│ │ │ │ ├── rax-app/
│ │ │ │ │ ├── demo01/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo02/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo03/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ ├── Detail/
│ │ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── Home/
│ │ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ └── List/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo04/
│ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo05/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo06-jsslot/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo07-newline-in-props/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo08-jsslot-with-multiple-children/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo09-jsslot-with-conditional-children/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo10-jsslot-with-loop-children/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo11-utils-name-alias/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Aaaa/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo12-refs/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Home/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ └── demo13-datasource-prop/
│ │ │ │ │ ├── expected/
│ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ ├── app.json
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── document/
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── global.css
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ └── Example/
│ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ └── schema.json5
│ │ │ │ ├── react-app/
│ │ │ │ │ ├── demo1/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo2/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo2-utils-name-alias/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Aaaa/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo3/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo4/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo5/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo6-literal-condition/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo7-literal-condition2/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo8-datasource-prop/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Example/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo9-datasource-engine/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── $/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ ├── demo_10-jsslot/
│ │ │ │ │ │ ├── expected/
│ │ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ │ └── schema.json5
│ │ │ │ │ └── demo_11-jsslot-2/
│ │ │ │ │ ├── expected/
│ │ │ │ │ │ └── demo-project/
│ │ │ │ │ │ ├── .editorconfig
│ │ │ │ │ │ ├── .eslintignore
│ │ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ │ ├── .gitignore
│ │ │ │ │ │ ├── .prettierignore
│ │ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ ├── abc.json
│ │ │ │ │ │ ├── build.json
│ │ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ │ ├── package.json
│ │ │ │ │ │ ├── public/
│ │ │ │ │ │ │ └── index.html
│ │ │ │ │ │ ├── src/
│ │ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── tsconfig.json
│ │ │ │ │ └── schema.json5
│ │ │ │ └── react-module/
│ │ │ │ └── demo1/
│ │ │ │ ├── expected/
│ │ │ │ │ └── demo-project/
│ │ │ │ │ ├── .editorconfig
│ │ │ │ │ ├── .eslintignore
│ │ │ │ │ ├── .eslintrc.js
│ │ │ │ │ ├── .gitignore
│ │ │ │ │ ├── .prettierignore
│ │ │ │ │ ├── .prettierrc.js
│ │ │ │ │ ├── .stylelintignore
│ │ │ │ │ ├── .stylelintrc.js
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── abc.json
│ │ │ │ │ ├── build.json
│ │ │ │ │ ├── jsconfig.json
│ │ │ │ │ ├── package.json
│ │ │ │ │ ├── public/
│ │ │ │ │ │ └── index.html
│ │ │ │ │ ├── src/
│ │ │ │ │ │ ├── app.js
│ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ ├── global.scss
│ │ │ │ │ │ ├── i18n.js
│ │ │ │ │ │ ├── layouts/
│ │ │ │ │ │ │ └── BasicLayout/
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── Footer/
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ ├── Logo/
│ │ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ │ └── index.module.scss
│ │ │ │ │ │ │ │ └── PageNav/
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ └── menuConfig.js
│ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ └── Test/
│ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── routes.js
│ │ │ │ │ │ └── utils.js
│ │ │ │ │ └── tsconfig.json
│ │ │ │ └── schema.json5
│ │ │ ├── helpers/
│ │ │ │ └── solutionHelper.ts
│ │ │ ├── plugins/
│ │ │ │ ├── common/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── requireUtils.test.ts.snap
│ │ │ │ │ └── requireUtils.test.ts
│ │ │ │ └── jsx/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── p0-condition-at-root.test.ts.snap
│ │ │ │ └── p0-condition-at-root.test.ts
│ │ │ ├── postprocessor/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── prettier.test.ts.snap
│ │ │ │ └── prettier.test.ts
│ │ │ ├── public/
│ │ │ │ ├── README.md
│ │ │ │ ├── SchemaParser/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── p0-basic.test.ts.snap
│ │ │ │ │ ├── data/
│ │ │ │ │ │ └── schema-with-slot.json
│ │ │ │ │ └── p0-basic.test.ts
│ │ │ │ ├── cli.test.ts
│ │ │ │ ├── publisher/
│ │ │ │ │ ├── disk/
│ │ │ │ │ │ └── disk.test.ts
│ │ │ │ │ └── zip/
│ │ │ │ │ └── zip.test.ts
│ │ │ │ └── solutions/
│ │ │ │ ├── icejs3-app.test.ts
│ │ │ │ ├── rax-app.test.ts
│ │ │ │ └── react-app.test.ts
│ │ │ └── utils/
│ │ │ ├── compositeType.test.ts
│ │ │ ├── errors.test.ts
│ │ │ ├── expressionParser/
│ │ │ │ ├── jsExpression.test.ts
│ │ │ │ ├── parseExpressionConvertThis2Context.test.ts
│ │ │ │ ├── parseExpressionGetGlobalVariables.test.ts
│ │ │ │ └── parseExpressionGetKeywords.test.ts
│ │ │ ├── flattenResult.test.ts
│ │ │ ├── resultHelper/
│ │ │ │ ├── example-result.json
│ │ │ │ ├── findFile.test.ts
│ │ │ │ ├── globFiles.test.ts
│ │ │ │ ├── removeDirsFromResult.test.ts
│ │ │ │ ├── removeFilesFromResult.test.ts
│ │ │ │ └── scanFiles.test.ts
│ │ │ ├── schema/
│ │ │ │ ├── data/
│ │ │ │ │ └── schema-with-slot.json
│ │ │ │ └── handleSubNodes.test.ts
│ │ │ ├── validate.test.ts
│ │ │ └── version.test.ts
│ │ └── tsconfig.json
│ └── material-parser/
│ ├── README.md
│ ├── build.test.json
│ ├── demo/
│ │ ├── component.jsx
│ │ ├── component.tsx
│ │ ├── parse-jsx.js
│ │ └── parse-tsx.js
│ ├── jest.config.js
│ ├── package.json
│ ├── schemas/
│ │ ├── schema.json
│ │ └── schema.yml
│ ├── scripts/
│ │ └── transform.js
│ ├── src/
│ │ ├── core/
│ │ │ ├── index.ts
│ │ │ └── schema/
│ │ │ └── types.ts
│ │ ├── generate.ts
│ │ ├── index.ts
│ │ ├── localize.ts
│ │ ├── parse/
│ │ │ ├── dynamic/
│ │ │ │ ├── index.ts
│ │ │ │ └── requireInSandbox.ts
│ │ │ ├── index.ts
│ │ │ ├── js/
│ │ │ │ ├── handlers/
│ │ │ │ │ ├── defaultPropsHandler.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── preProcessHandler.ts
│ │ │ │ │ ├── propTypeHandler.ts
│ │ │ │ │ └── propTypeJsDocHandler.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── resolver/
│ │ │ │ │ ├── checkIsIIFE.ts
│ │ │ │ │ ├── findAssignedMethods.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── isReactComponentStaticMember.ts
│ │ │ │ │ ├── isStaticMethod.ts
│ │ │ │ │ ├── resolveExportDeclaration.ts
│ │ │ │ │ ├── resolveHOC.ts
│ │ │ │ │ ├── resolveIIFE.ts
│ │ │ │ │ ├── resolveImport.ts
│ │ │ │ │ └── resolveTranspiledClass.ts
│ │ │ │ └── utils/
│ │ │ │ ├── cache.ts
│ │ │ │ ├── evaluate.ts
│ │ │ │ ├── findJSFilePath.ts
│ │ │ │ ├── getComposedPath.ts
│ │ │ │ ├── getName.ts
│ │ │ │ ├── getRoot.ts
│ │ │ │ └── makeProxy.ts
│ │ │ ├── transform.ts
│ │ │ └── ts/
│ │ │ ├── generateDTS.ts
│ │ │ ├── index.ts
│ │ │ └── tsconfig.json
│ │ ├── scan.ts
│ │ ├── types/
│ │ │ ├── Basic.ts
│ │ │ ├── ChannelType.ts
│ │ │ ├── DSLType.ts
│ │ │ ├── IAccesser.ts
│ │ │ ├── IExtensionConfigManifest.ts
│ │ │ ├── IMaterialParsedModel.ts
│ │ │ ├── IMaterialScanModel.ts
│ │ │ ├── IMaterializeOptions.ts
│ │ │ ├── Meta.ts
│ │ │ └── index.ts
│ │ ├── utils.ts
│ │ └── validate/
│ │ ├── index.ts
│ │ └── schema.json
│ ├── test/
│ │ ├── __snapshots__/
│ │ │ ├── dynamic.test.ts.snap
│ │ │ ├── index.test.ts.snap
│ │ │ └── online.test.ts.snap
│ │ ├── dynamic.test.ts
│ │ ├── fixtures/
│ │ │ ├── dts-component/
│ │ │ │ ├── index.d.ts
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── data.js
│ │ │ │ ├── i18n.js
│ │ │ │ ├── index.jsx
│ │ │ │ ├── main.scss
│ │ │ │ └── scss/
│ │ │ │ └── variable.scss
│ │ │ ├── multiple-exported-component/
│ │ │ │ ├── es/
│ │ │ │ │ ├── basic/
│ │ │ │ │ │ ├── AIMakeBlank/
│ │ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ │ └── manifest.json
│ │ │ │ │ │ ├── AIMakeIcon/
│ │ │ │ │ │ │ ├── IconFont.js
│ │ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ │ └── manifest.json
│ │ │ │ │ │ ├── AIMakeImage/
│ │ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ │ └── manifest.json
│ │ │ │ │ │ ├── AIMakeLink/
│ │ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ │ └── manifest.json
│ │ │ │ │ │ ├── AIMakePlaceholder/
│ │ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ │ └── manifest.json
│ │ │ │ │ │ ├── AIMakeText/
│ │ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ │ └── manifest.json
│ │ │ │ │ │ ├── Root/
│ │ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ │ └── manifest.json
│ │ │ │ │ │ ├── style/
│ │ │ │ │ │ │ ├── index.css
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ └── index.less
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── HOCBackgroundProps.js
│ │ │ │ │ │ ├── HOCBoxModelProps.js
│ │ │ │ │ │ ├── HOCFlexLayoutProps.js
│ │ │ │ │ │ ├── HOCLayoutProps.js
│ │ │ │ │ │ └── HOCTextProps.js
│ │ │ │ │ └── index.js
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── basic/
│ │ │ │ │ ├── AIMakeBlank/
│ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ └── manifest.json
│ │ │ │ │ ├── AIMakeIcon/
│ │ │ │ │ │ ├── IconFont.js
│ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ └── manifest.json
│ │ │ │ │ ├── AIMakeImage/
│ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ └── manifest.json
│ │ │ │ │ ├── AIMakeLink/
│ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ └── manifest.json
│ │ │ │ │ ├── AIMakePlaceholder/
│ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ └── manifest.json
│ │ │ │ │ ├── AIMakeText/
│ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ └── manifest.json
│ │ │ │ │ ├── Root/
│ │ │ │ │ │ ├── amContainer.js
│ │ │ │ │ │ ├── amManifest.js
│ │ │ │ │ │ ├── container.js
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── manifest.js
│ │ │ │ │ │ └── manifest.json
│ │ │ │ │ ├── style/
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ └── index.less
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── HOCBackgroundProps.js
│ │ │ │ │ ├── HOCBoxModelProps.js
│ │ │ │ │ ├── HOCFlexLayoutProps.js
│ │ │ │ │ ├── HOCLayoutProps.js
│ │ │ │ │ └── HOCTextProps.js
│ │ │ │ └── index.js
│ │ │ ├── rax-component/
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── single-exported-component/
│ │ │ │ ├── es/
│ │ │ │ │ ├── container.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── main.css
│ │ │ │ │ ├── main.scss
│ │ │ │ │ ├── manifest.js
│ │ │ │ │ └── manifest.json
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── index.js
│ │ │ │ └── main.scss
│ │ │ ├── transpiled-component/
│ │ │ │ └── package.json
│ │ │ ├── ts-component/
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── main-module.tsx
│ │ │ │ └── sub-module.tsx
│ │ │ ├── ts-component2/
│ │ │ │ ├── package.json
│ │ │ │ └── src/
│ │ │ │ ├── empty.tsx
│ │ │ │ ├── index.scss
│ │ │ │ └── index.tsx
│ │ │ └── without-display-name/
│ │ │ ├── index.js
│ │ │ └── package.json
│ │ ├── helpers/
│ │ │ └── index.ts
│ │ ├── index.test.ts
│ │ ├── localize.test.ts
│ │ ├── online.test.ts
│ │ └── validate/
│ │ ├── __snapshots__/
│ │ │ └── index.test.ts.snap
│ │ ├── fixtures/
│ │ │ ├── basic-error/
│ │ │ │ └── schema.json
│ │ │ ├── basic-success/
│ │ │ │ └── schema.json
│ │ │ ├── configure/
│ │ │ │ └── schema.json
│ │ │ ├── props-basic-type/
│ │ │ │ └── schema.json
│ │ │ └── props-complex-type/
│ │ │ └── schema.json
│ │ └── index.test.ts
│ ├── tsconfig.json
│ └── webpack.config.js
├── package.json
├── packages/
│ ├── designer/
│ │ ├── README.md
│ │ ├── babel.config.js
│ │ ├── build.json
│ │ ├── build.test.json
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── builtin-simulator/
│ │ │ │ ├── README.md
│ │ │ │ ├── bem-tools/
│ │ │ │ │ ├── bem-tools.less
│ │ │ │ │ ├── border-container.tsx
│ │ │ │ │ ├── border-detecting.tsx
│ │ │ │ │ ├── border-resizing.tsx
│ │ │ │ │ ├── border-selecting.tsx
│ │ │ │ │ ├── borders.less
│ │ │ │ │ ├── drag-resize-engine.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── insertion.less
│ │ │ │ │ ├── insertion.tsx
│ │ │ │ │ └── manager.ts
│ │ │ │ ├── context.ts
│ │ │ │ ├── create-simulator.ts
│ │ │ │ ├── host-view.tsx
│ │ │ │ ├── host.less
│ │ │ │ ├── host.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── live-editing/
│ │ │ │ │ └── live-editing.ts
│ │ │ │ ├── node-selector/
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── renderer.ts
│ │ │ │ ├── resource-consumer.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── clickable.ts
│ │ │ │ │ ├── parse-metadata.ts
│ │ │ │ │ ├── path.ts
│ │ │ │ │ └── throttle.ts
│ │ │ │ └── viewport.ts
│ │ │ ├── component-actions.ts
│ │ │ ├── component-meta.ts
│ │ │ ├── context-menu-actions.scss
│ │ │ ├── context-menu-actions.ts
│ │ │ ├── designer/
│ │ │ │ ├── active-tracker.ts
│ │ │ │ ├── clipboard.ts
│ │ │ │ ├── designer-view.tsx
│ │ │ │ ├── designer.less
│ │ │ │ ├── designer.ts
│ │ │ │ ├── detecting.ts
│ │ │ │ ├── drag-ghost/
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── ghost.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── dragon.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── location.ts
│ │ │ │ ├── offset-observer.ts
│ │ │ │ ├── scroller.ts
│ │ │ │ └── setting/
│ │ │ │ ├── index.ts
│ │ │ │ ├── setting-entry-type.ts
│ │ │ │ ├── setting-field.ts
│ │ │ │ ├── setting-prop-entry.ts
│ │ │ │ ├── setting-top-entry.ts
│ │ │ │ └── utils.ts
│ │ │ ├── document/
│ │ │ │ ├── document-model.ts
│ │ │ │ ├── document-view.tsx
│ │ │ │ ├── history.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── node/
│ │ │ │ │ ├── exclusive-group.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── modal-nodes-manager.ts
│ │ │ │ │ ├── node-children.ts
│ │ │ │ │ ├── node.ts
│ │ │ │ │ ├── props/
│ │ │ │ │ │ ├── prop.ts
│ │ │ │ │ │ ├── props.ts
│ │ │ │ │ │ └── value-to-source.ts
│ │ │ │ │ └── transform-stage.ts
│ │ │ │ └── selection.ts
│ │ │ ├── icons/
│ │ │ │ ├── clone.tsx
│ │ │ │ ├── component.tsx
│ │ │ │ ├── container.tsx
│ │ │ │ ├── hidden.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── lock.tsx
│ │ │ │ ├── page.tsx
│ │ │ │ ├── remove.tsx
│ │ │ │ ├── setting.tsx
│ │ │ │ └── unlock.tsx
│ │ │ ├── index.ts
│ │ │ ├── less-variables.less
│ │ │ ├── locale/
│ │ │ │ ├── en-US.json
│ │ │ │ ├── index.ts
│ │ │ │ └── zh-CN.json
│ │ │ ├── plugin/
│ │ │ │ ├── index.ts
│ │ │ │ ├── plugin-context.ts
│ │ │ │ ├── plugin-manager.ts
│ │ │ │ ├── plugin-types.ts
│ │ │ │ ├── plugin-utils.ts
│ │ │ │ ├── plugin.ts
│ │ │ │ └── sequencify.ts
│ │ │ ├── project/
│ │ │ │ ├── index.ts
│ │ │ │ ├── project-view.tsx
│ │ │ │ ├── project.less
│ │ │ │ └── project.ts
│ │ │ ├── simulator.ts
│ │ │ ├── transducers/
│ │ │ │ └── index.ts
│ │ │ ├── types/
│ │ │ │ └── index.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ ├── invariant.ts
│ │ │ ├── misc.ts
│ │ │ ├── slot.ts
│ │ │ └── tree.ts
│ │ ├── tests/
│ │ │ ├── __mocks__/
│ │ │ │ ├── document-model.ts
│ │ │ │ └── node.ts
│ │ │ ├── bugs/
│ │ │ │ ├── misc.ts.bak
│ │ │ │ ├── prop-variable-jse.test.ts
│ │ │ │ └── why.md
│ │ │ ├── builtin-simulator/
│ │ │ │ ├── bem-tools/
│ │ │ │ │ ├── drag-resize-engine.test.ts
│ │ │ │ │ └── manager.test.tsx
│ │ │ │ ├── host.test.ts
│ │ │ │ ├── renderer.test.tsx
│ │ │ │ ├── resource-consumer.test.ts
│ │ │ │ ├── utils/
│ │ │ │ │ ├── parse-metadata.test.ts
│ │ │ │ │ ├── path.test.ts
│ │ │ │ │ └── throttle.test.ts
│ │ │ │ └── viewport.test.ts
│ │ │ ├── designer/
│ │ │ │ ├── active-tracker.test.ts
│ │ │ │ ├── builtin-hotkey.test.ts
│ │ │ │ ├── designer.test.ts
│ │ │ │ ├── detecting.test.ts
│ │ │ │ ├── dragon.test.ts
│ │ │ │ ├── location.test.ts
│ │ │ │ ├── scroller.test.ts
│ │ │ │ └── setting/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── setting-field.test.ts.snap
│ │ │ │ ├── setting-field.test.ts
│ │ │ │ ├── setting-prop-entry.test.ts
│ │ │ │ └── setting-top-entry.test.ts
│ │ │ ├── document/
│ │ │ │ ├── document-model/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── document-model.test.ts.snap
│ │ │ │ │ └── document-model.test.ts
│ │ │ │ ├── history/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── history.test.ts.snap
│ │ │ │ │ ├── history.test.ts
│ │ │ │ │ └── session.test.ts
│ │ │ │ ├── node/
│ │ │ │ │ ├── modal-nodes-manager.test.ts
│ │ │ │ │ ├── node-children.test.ts
│ │ │ │ │ ├── node.add.test.ts
│ │ │ │ │ ├── node.dragdrop.test.ts
│ │ │ │ │ ├── node.modify.test.ts
│ │ │ │ │ ├── node.remove.test.ts
│ │ │ │ │ ├── node.test.ts
│ │ │ │ │ └── props/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── value-to-source.test.ts.snap
│ │ │ │ │ ├── prop.test.ts
│ │ │ │ │ ├── props.test.ts
│ │ │ │ │ └── value-to-source.test.ts
│ │ │ │ └── selection.test.ts
│ │ │ ├── fixtures/
│ │ │ │ ├── component-metadata/
│ │ │ │ │ ├── abcgroup.ts
│ │ │ │ │ ├── abcitem.ts
│ │ │ │ │ ├── abcnode.ts
│ │ │ │ │ ├── abcoption.ts
│ │ │ │ │ ├── button.ts
│ │ │ │ │ ├── dialog.ts
│ │ │ │ │ ├── div.ts
│ │ │ │ │ ├── div10.ts
│ │ │ │ │ ├── div2.ts
│ │ │ │ │ ├── div3.ts
│ │ │ │ │ ├── div4.ts
│ │ │ │ │ ├── div5.ts
│ │ │ │ │ ├── div6.ts
│ │ │ │ │ ├── div7.ts
│ │ │ │ │ ├── div8.ts
│ │ │ │ │ ├── div9.ts
│ │ │ │ │ ├── form.ts
│ │ │ │ │ ├── other.ts
│ │ │ │ │ ├── page.ts
│ │ │ │ │ ├── page2.ts
│ │ │ │ │ ├── root-content.ts
│ │ │ │ │ ├── root-footer.ts
│ │ │ │ │ └── root-header.ts
│ │ │ │ ├── disable-raf.ts
│ │ │ │ ├── schema/
│ │ │ │ │ ├── form-with-modal.ts
│ │ │ │ │ ├── form.ts
│ │ │ │ │ └── setting.ts
│ │ │ │ ├── silent-console.ts
│ │ │ │ ├── unhandled-rejection.ts
│ │ │ │ └── window.ts
│ │ │ ├── main/
│ │ │ │ ├── meta/
│ │ │ │ │ └── component-meta.test.ts
│ │ │ │ └── simulator.test.ts
│ │ │ ├── plugin/
│ │ │ │ ├── plugin-manager.test.ts
│ │ │ │ ├── plugin-utils.test.ts
│ │ │ │ └── sequencify.test.ts
│ │ │ ├── project/
│ │ │ │ ├── project-methods.test.ts
│ │ │ │ └── project.test.ts
│ │ │ ├── utils/
│ │ │ │ ├── bom.ts
│ │ │ │ ├── event.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── misc.ts
│ │ │ │ └── renderer.ts
│ │ │ └── utils-ut/
│ │ │ ├── invariant.test.ts
│ │ │ ├── misc.test.ts
│ │ │ └── slot.test.ts
│ │ └── tsconfig.json
│ ├── editor-core/
│ │ ├── build.json
│ │ ├── build.plugin.js
│ │ ├── build.test.json
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── command.ts
│ │ │ ├── config.ts
│ │ │ ├── di/
│ │ │ │ ├── index.ts
│ │ │ │ ├── ioc-context.ts
│ │ │ │ └── setter.ts
│ │ │ ├── editor.ts
│ │ │ ├── event-bus.ts
│ │ │ ├── hotkey.ts
│ │ │ ├── index.ts
│ │ │ ├── intl/
│ │ │ │ ├── global-locale.ts
│ │ │ │ └── index.ts
│ │ │ ├── utils/
│ │ │ │ ├── app-preset.ts
│ │ │ │ ├── assets-transform.ts
│ │ │ │ ├── control.ts
│ │ │ │ ├── focus-tracker.ts
│ │ │ │ ├── get-public-path.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── logger.ts
│ │ │ │ ├── obx.ts
│ │ │ │ ├── preference.ts
│ │ │ │ └── request.ts
│ │ │ └── widgets/
│ │ │ ├── index.ts
│ │ │ ├── tip/
│ │ │ │ ├── help-tips.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── style.less
│ │ │ │ ├── tip-container.tsx
│ │ │ │ ├── tip-handler.ts
│ │ │ │ ├── tip-item.tsx
│ │ │ │ ├── tip.tsx
│ │ │ │ └── utils.ts
│ │ │ └── title/
│ │ │ ├── index.tsx
│ │ │ └── title.less
│ │ ├── test/
│ │ │ └── command.test.ts
│ │ └── tsconfig.json
│ ├── editor-skeleton/
│ │ ├── build.json
│ │ ├── build.test.json
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── area.ts
│ │ │ ├── components/
│ │ │ │ ├── draggable-line/
│ │ │ │ │ ├── index.less
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── field/
│ │ │ │ │ ├── fields.tsx
│ │ │ │ │ ├── index.less
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── inlinetip.tsx
│ │ │ │ ├── popup/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── style.less
│ │ │ │ ├── settings/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── main.ts
│ │ │ │ │ ├── settings-pane.tsx
│ │ │ │ │ ├── settings-primary-pane.tsx
│ │ │ │ │ ├── style.less
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── stage-box/
│ │ │ │ │ ├── index.less
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── stage-box.tsx
│ │ │ │ │ ├── stage-chain.ts
│ │ │ │ │ └── stage.tsx
│ │ │ │ └── widget-views/
│ │ │ │ ├── index.less
│ │ │ │ ├── index.tsx
│ │ │ │ └── panel-operation-row.tsx
│ │ │ ├── context.ts
│ │ │ ├── icons/
│ │ │ │ ├── arrow.tsx
│ │ │ │ ├── clear.tsx
│ │ │ │ ├── convert.tsx
│ │ │ │ ├── exit.tsx
│ │ │ │ ├── fix.tsx
│ │ │ │ ├── float.tsx
│ │ │ │ ├── slot.tsx
│ │ │ │ └── variable.tsx
│ │ │ ├── index.ts
│ │ │ ├── layouts/
│ │ │ │ ├── bottom-area.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── left-area.tsx
│ │ │ │ ├── left-fixed-pane.tsx
│ │ │ │ ├── left-float-pane.tsx
│ │ │ │ ├── main-area.tsx
│ │ │ │ ├── right-area.tsx
│ │ │ │ ├── sub-top-area.tsx
│ │ │ │ ├── theme.less
│ │ │ │ ├── toolbar.tsx
│ │ │ │ ├── top-area.tsx
│ │ │ │ ├── workbench.less
│ │ │ │ └── workbench.tsx
│ │ │ ├── less-variables.less
│ │ │ ├── locale/
│ │ │ │ ├── en-US.json
│ │ │ │ ├── index.ts
│ │ │ │ └── zh-CN.json
│ │ │ ├── register-defaults.ts
│ │ │ ├── skeleton.ts
│ │ │ ├── transducers/
│ │ │ │ ├── addon-combine.ts
│ │ │ │ ├── parse-func.ts
│ │ │ │ └── parse-props.ts
│ │ │ ├── types.ts
│ │ │ └── widget/
│ │ │ ├── dialog-dock.ts
│ │ │ ├── dock.ts
│ │ │ ├── index.ts
│ │ │ ├── panel-dock.ts
│ │ │ ├── panel.ts
│ │ │ ├── stage.ts
│ │ │ ├── utils.ts
│ │ │ ├── widget-container.ts
│ │ │ └── widget.ts
│ │ ├── tests/
│ │ │ └── widget/
│ │ │ └── utils.test.ts
│ │ └── tsconfig.json
│ ├── engine/
│ │ ├── README-zh_CN.md
│ │ ├── README.md
│ │ ├── babel.config.js
│ │ ├── build.json
│ │ ├── build.plugin.js
│ │ ├── build.test.json
│ │ ├── build.umd.json
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── engine-core.ts
│ │ │ ├── index.ts
│ │ │ ├── inner-plugins/
│ │ │ │ ├── builtin-hotkey.ts
│ │ │ │ ├── component-meta-parser.ts
│ │ │ │ ├── default-context-menu.ts
│ │ │ │ ├── default-panel-registry.tsx
│ │ │ │ └── setter-registry.ts
│ │ │ ├── locale/
│ │ │ │ ├── en-US.json
│ │ │ │ ├── index.ts
│ │ │ │ └── zh-CN.json
│ │ │ └── modules/
│ │ │ ├── classes.ts
│ │ │ ├── designer-types.ts
│ │ │ ├── live-editing.ts
│ │ │ ├── lowcode-types.ts
│ │ │ ├── shell-model-factory.ts
│ │ │ ├── skeleton-types.ts
│ │ │ └── symbols.ts
│ │ └── tsconfig.json
│ ├── ignitor/
│ │ ├── babel.config.js
│ │ ├── build.json
│ │ ├── build.plugin.js
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── public/
│ │ │ └── index.html
│ │ └── tsconfig.json
│ ├── plugin-command/
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── node-command.test.ts
│ │ ├── build.json
│ │ ├── build.test.json
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ └── src/
│ │ ├── history-command.ts
│ │ ├── index.ts
│ │ └── node-command.ts
│ ├── plugin-designer/
│ │ ├── .gitignore
│ │ ├── build.json
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.scss
│ │ │ └── index.tsx
│ │ └── tsconfig.json
│ ├── plugin-outline-pane/
│ │ ├── .gitignore
│ │ ├── build.json
│ │ ├── package.json
│ │ └── src/
│ │ ├── README.md
│ │ ├── controllers/
│ │ │ ├── pane-controller.ts
│ │ │ ├── ric-shim.d.ts
│ │ │ ├── tree-master.ts
│ │ │ ├── tree-node.ts
│ │ │ └── tree.ts
│ │ ├── helper/
│ │ │ ├── consts.ts
│ │ │ ├── dwell-timer.ts
│ │ │ └── indent-track.ts
│ │ ├── icons/
│ │ │ ├── arrow-right.tsx
│ │ │ ├── cond.tsx
│ │ │ ├── delete.tsx
│ │ │ ├── eye-close.tsx
│ │ │ ├── eye.tsx
│ │ │ ├── filter.tsx
│ │ │ ├── index.ts
│ │ │ ├── lock.tsx
│ │ │ ├── loop.tsx
│ │ │ ├── outline.tsx
│ │ │ ├── radio-active.tsx
│ │ │ ├── radio.tsx
│ │ │ ├── setting.tsx
│ │ │ └── unlock.tsx
│ │ ├── index.tsx
│ │ ├── locale/
│ │ │ ├── en-US.json
│ │ │ ├── index.ts
│ │ │ └── zh-CN.json
│ │ └── views/
│ │ ├── filter-tree.ts
│ │ ├── filter.tsx
│ │ ├── pane.tsx
│ │ ├── style.less
│ │ ├── tree-branches.tsx
│ │ ├── tree-node.tsx
│ │ ├── tree-title.tsx
│ │ └── tree.tsx
│ ├── react-renderer/
│ │ ├── README.md
│ │ ├── build.json
│ │ ├── build.test.json
│ │ ├── build.umd.json
│ │ ├── demo/
│ │ │ ├── compose.md
│ │ │ ├── config/
│ │ │ │ ├── components/
│ │ │ │ │ ├── A.jsx
│ │ │ │ │ ├── Div.jsx
│ │ │ │ │ ├── Image.jsx
│ │ │ │ │ ├── Text.jsx
│ │ │ │ │ └── index.js
│ │ │ │ ├── constants.js
│ │ │ │ └── utils.js
│ │ │ ├── dataSource.md
│ │ │ ├── i18n.md
│ │ │ ├── list.md
│ │ │ ├── schemas/
│ │ │ │ ├── compose.js
│ │ │ │ ├── dataSource.js
│ │ │ │ ├── i18n.js
│ │ │ │ ├── list.js
│ │ │ │ └── table.js
│ │ │ └── table.md
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── tests/
│ │ │ ├── __snapshots__/
│ │ │ │ └── index.test.tsx.snap
│ │ │ ├── fixtures/
│ │ │ │ └── schema/
│ │ │ │ └── basic.ts
│ │ │ └── index.test.tsx
│ │ └── tsconfig.json
│ ├── react-simulator-renderer/
│ │ ├── .babelrc
│ │ ├── babel.config.js
│ │ ├── build.json
│ │ ├── build.plugin.js
│ │ ├── build.test.json
│ │ ├── build.umd.json
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── README.md
│ │ │ ├── builtin-components/
│ │ │ │ ├── builtin-components.ts
│ │ │ │ ├── leaf.tsx
│ │ │ │ └── slot.tsx
│ │ │ ├── host.ts
│ │ │ ├── index.ts
│ │ │ ├── locale/
│ │ │ │ ├── en-US.json
│ │ │ │ ├── index.ts
│ │ │ │ └── zh-CN.json
│ │ │ ├── renderer-view.tsx
│ │ │ ├── renderer.less
│ │ │ ├── renderer.ts
│ │ │ └── utils/
│ │ │ ├── get-client-rects.ts
│ │ │ ├── is-dom-node.ts
│ │ │ ├── misc.ts
│ │ │ ├── react-find-dom-nodes.ts
│ │ │ └── url.ts
│ │ ├── test/
│ │ │ ├── schema/
│ │ │ │ └── basic.ts
│ │ │ ├── src/
│ │ │ │ └── renderer/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── demo.test.tsx.snap
│ │ │ │ └── demo.test.tsx
│ │ │ └── utils/
│ │ │ ├── components.tsx
│ │ │ └── host.ts
│ │ └── tsconfig.json
│ ├── renderer-core/
│ │ ├── babel.config.js
│ │ ├── build.json
│ │ ├── build.test.json
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── adapter/
│ │ │ │ └── index.ts
│ │ │ ├── components/
│ │ │ │ ├── Div.tsx
│ │ │ │ └── VisualDom/
│ │ │ │ ├── index.css
│ │ │ │ └── index.tsx
│ │ │ ├── context/
│ │ │ │ └── index.ts
│ │ │ ├── hoc/
│ │ │ │ ├── index.tsx
│ │ │ │ └── leaf.tsx
│ │ │ ├── index.ts
│ │ │ ├── renderer/
│ │ │ │ ├── addon.tsx
│ │ │ │ ├── base.tsx
│ │ │ │ ├── block.tsx
│ │ │ │ ├── component.tsx
│ │ │ │ ├── index.ts
│ │ │ │ ├── page.tsx
│ │ │ │ ├── renderer.tsx
│ │ │ │ └── temp.tsx
│ │ │ ├── types/
│ │ │ │ └── index.ts
│ │ │ └── utils/
│ │ │ ├── common.ts
│ │ │ ├── data-helper.ts
│ │ │ ├── index.ts
│ │ │ ├── is-use-loop.ts
│ │ │ ├── logger.ts
│ │ │ └── request.ts
│ │ ├── tests/
│ │ │ ├── adapter/
│ │ │ │ └── adapter.test.ts
│ │ │ ├── fixtures/
│ │ │ │ ├── schema/
│ │ │ │ │ └── basic.ts
│ │ │ │ └── unhandled-rejection.ts
│ │ │ ├── hoc/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── leaf.test.tsx.snap
│ │ │ │ └── leaf.test.tsx
│ │ │ ├── mock/
│ │ │ │ ├── loop.ts
│ │ │ │ ├── sample.ts
│ │ │ │ └── styleMock.js
│ │ │ ├── renderer/
│ │ │ │ ├── __snapshots__/
│ │ │ │ │ └── renderer.test.tsx.snap
│ │ │ │ ├── base.test.tsx
│ │ │ │ └── renderer.test.tsx
│ │ │ ├── setup.ts
│ │ │ └── utils/
│ │ │ ├── common.test.ts
│ │ │ ├── components.tsx
│ │ │ ├── data-helper.test.ts
│ │ │ ├── is-use-loop.test.ts
│ │ │ ├── node.ts
│ │ │ ├── react-env-init.ts
│ │ │ └── request.test.ts
│ │ └── tsconfig.json
│ ├── shell/
│ │ ├── build.json
│ │ ├── build.test.json
│ │ ├── package.json
│ │ └── src/
│ │ ├── api/
│ │ │ ├── canvas.ts
│ │ │ ├── command.ts
│ │ │ ├── common.tsx
│ │ │ ├── commonUI.tsx
│ │ │ ├── config.ts
│ │ │ ├── event.ts
│ │ │ ├── hotkey.ts
│ │ │ ├── index.ts
│ │ │ ├── logger.ts
│ │ │ ├── material.ts
│ │ │ ├── plugins.ts
│ │ │ ├── project.ts
│ │ │ ├── setters.ts
│ │ │ ├── simulator-host.ts
│ │ │ ├── skeleton.ts
│ │ │ └── workspace.ts
│ │ ├── components/
│ │ │ └── context-menu.tsx
│ │ ├── index.ts
│ │ ├── model/
│ │ │ ├── active-tracker.ts
│ │ │ ├── clipboard.ts
│ │ │ ├── component-meta.ts
│ │ │ ├── condition-group.ts
│ │ │ ├── detecting.ts
│ │ │ ├── document-model.ts
│ │ │ ├── drag-object.ts
│ │ │ ├── dragon.ts
│ │ │ ├── drop-location.ts
│ │ │ ├── editor-view.ts
│ │ │ ├── history.ts
│ │ │ ├── index.ts
│ │ │ ├── locate-event.ts
│ │ │ ├── modal-nodes-manager.ts
│ │ │ ├── node-children.ts
│ │ │ ├── node.ts
│ │ │ ├── plugin-instance.ts
│ │ │ ├── prop.ts
│ │ │ ├── props.ts
│ │ │ ├── resource.ts
│ │ │ ├── selection.ts
│ │ │ ├── setting-field.ts
│ │ │ ├── setting-top-entry.ts
│ │ │ ├── simulator-render.ts
│ │ │ ├── skeleton-item.ts
│ │ │ └── window.ts
│ │ └── symbols.ts
│ ├── types/
│ │ ├── .eslintignore
│ │ ├── .prettierrc.js
│ │ ├── CHANGELOG.md
│ │ ├── build.json
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── activity.ts
│ │ │ ├── assets.ts
│ │ │ ├── code-intermediate.ts
│ │ │ ├── code-result.ts
│ │ │ ├── deprecated/
│ │ │ │ ├── index.ts
│ │ │ │ ├── isActionContentObject.ts
│ │ │ │ ├── isCustomView.ts
│ │ │ │ ├── isDOMText.ts
│ │ │ │ ├── isDynamicSetter.ts
│ │ │ │ ├── isI18nData.ts
│ │ │ │ ├── isJSBlock.ts
│ │ │ │ ├── isJSExpression.ts
│ │ │ │ ├── isJSFunction.ts
│ │ │ │ ├── isJSSlot.ts
│ │ │ │ ├── isLowCodeComponentType.ts
│ │ │ │ ├── isNodeSchema.ts
│ │ │ │ ├── isPlainObject.ts
│ │ │ │ ├── isProCodeComponentType.ts
│ │ │ │ ├── isProjectSchema.ts
│ │ │ │ ├── isReactClass.ts
│ │ │ │ ├── isReactComponent.ts
│ │ │ │ ├── isSetterConfig.ts
│ │ │ │ └── isTitleConfig.ts
│ │ │ ├── editor.ts
│ │ │ ├── event/
│ │ │ │ ├── index.ts
│ │ │ │ ├── node.ts
│ │ │ │ └── prop.ts
│ │ │ ├── index.ts
│ │ │ ├── shell/
│ │ │ │ ├── api/
│ │ │ │ │ ├── canvas.ts
│ │ │ │ │ ├── command.ts
│ │ │ │ │ ├── common.ts
│ │ │ │ │ ├── commonUI.ts
│ │ │ │ │ ├── event.ts
│ │ │ │ │ ├── hotkey.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── logger.ts
│ │ │ │ │ ├── material.ts
│ │ │ │ │ ├── plugins.ts
│ │ │ │ │ ├── project.ts
│ │ │ │ │ ├── setters.ts
│ │ │ │ │ ├── simulator-host.ts
│ │ │ │ │ ├── skeleton.ts
│ │ │ │ │ └── workspace.ts
│ │ │ │ ├── enum/
│ │ │ │ │ ├── context-menu.ts
│ │ │ │ │ ├── drag-object-type.ts
│ │ │ │ │ ├── event-names.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── plugin-register-level.ts
│ │ │ │ │ ├── prop-value-changed-type.ts
│ │ │ │ │ ├── transform-stage.ts
│ │ │ │ │ └── transition-type.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── model/
│ │ │ │ │ ├── active-tracker.ts
│ │ │ │ │ ├── clipboard.ts
│ │ │ │ │ ├── component-meta.ts
│ │ │ │ │ ├── detecting.ts
│ │ │ │ │ ├── document-model.ts
│ │ │ │ │ ├── drag-object.ts
│ │ │ │ │ ├── dragon.ts
│ │ │ │ │ ├── drop-location.ts
│ │ │ │ │ ├── editor-view.ts
│ │ │ │ │ ├── editor.ts
│ │ │ │ │ ├── engine-config.ts
│ │ │ │ │ ├── exclusive-group.ts
│ │ │ │ │ ├── history.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── locate-event.ts
│ │ │ │ │ ├── modal-nodes-manager.ts
│ │ │ │ │ ├── node-children.ts
│ │ │ │ │ ├── node.ts
│ │ │ │ │ ├── plugin-context.ts
│ │ │ │ │ ├── plugin-instance.ts
│ │ │ │ │ ├── preference.ts
│ │ │ │ │ ├── prop.ts
│ │ │ │ │ ├── props.ts
│ │ │ │ │ ├── resource.ts
│ │ │ │ │ ├── scroll-target.ts
│ │ │ │ │ ├── scroller.ts
│ │ │ │ │ ├── selection.ts
│ │ │ │ │ ├── sensor.ts
│ │ │ │ │ ├── setting-field.ts
│ │ │ │ │ ├── setting-prop-entry.ts
│ │ │ │ │ ├── setting-target.ts
│ │ │ │ │ ├── setting-top-entry.ts
│ │ │ │ │ ├── simulator-render.ts
│ │ │ │ │ ├── skeleton-item.ts
│ │ │ │ │ └── window.ts
│ │ │ │ └── type/
│ │ │ │ ├── action-content-object.ts
│ │ │ │ ├── active-target.ts
│ │ │ │ ├── advanced.ts
│ │ │ │ ├── app-config.ts
│ │ │ │ ├── assets-json.ts
│ │ │ │ ├── block-schema.ts
│ │ │ │ ├── command.ts
│ │ │ │ ├── component-action.ts
│ │ │ │ ├── component-description.ts
│ │ │ │ ├── component-instance.ts
│ │ │ │ ├── component-metadata.ts
│ │ │ │ ├── component-schema.ts
│ │ │ │ ├── component-sort.ts
│ │ │ │ ├── composite-value.ts
│ │ │ │ ├── config-transducer.ts
│ │ │ │ ├── configure.ts
│ │ │ │ ├── container-schema.ts
│ │ │ │ ├── context-menu.ts
│ │ │ │ ├── custom-view.ts
│ │ │ │ ├── disposable.ts
│ │ │ │ ├── dom-text.ts
│ │ │ │ ├── drag-any-object.ts
│ │ │ │ ├── drag-node-data-object.ts
│ │ │ │ ├── drag-node-object.ts
│ │ │ │ ├── drag-object.ts
│ │ │ │ ├── dynamic-props.ts
│ │ │ │ ├── dynamic-setter.ts
│ │ │ │ ├── editor-get-options.ts
│ │ │ │ ├── editor-get-result.ts
│ │ │ │ ├── editor-register-options.ts
│ │ │ │ ├── editor-value-key.ts
│ │ │ │ ├── editor-view-config.ts
│ │ │ │ ├── editor-view.ts
│ │ │ │ ├── engine-options.ts
│ │ │ │ ├── field-config.ts
│ │ │ │ ├── field-extra-props.ts
│ │ │ │ ├── hotkey-callback-config.ts
│ │ │ │ ├── hotkey-callback.ts
│ │ │ │ ├── hotkey-callbacks.ts
│ │ │ │ ├── i18n-map.ts
│ │ │ │ ├── i8n-data.ts
│ │ │ │ ├── icon-config.ts
│ │ │ │ ├── icon-type.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── location.ts
│ │ │ │ ├── metadata-transducer.ts
│ │ │ │ ├── metadata.ts
│ │ │ │ ├── node-data-type.ts
│ │ │ │ ├── node-data.ts
│ │ │ │ ├── node-instance.ts
│ │ │ │ ├── node-schema.ts
│ │ │ │ ├── npm-info.ts
│ │ │ │ ├── npm.ts
│ │ │ │ ├── on-change-options.ts
│ │ │ │ ├── package.ts
│ │ │ │ ├── page-schema.ts
│ │ │ │ ├── plugin-config.ts
│ │ │ │ ├── plugin-creater.ts
│ │ │ │ ├── plugin-declaration-property.ts
│ │ │ │ ├── plugin-declaration.ts
│ │ │ │ ├── plugin-meta.ts
│ │ │ │ ├── plugin-register-options.ts
│ │ │ │ ├── plugin.ts
│ │ │ │ ├── preference-value-type.ts
│ │ │ │ ├── project-schema.ts
│ │ │ │ ├── prop-change-options.ts
│ │ │ │ ├── prop-config.ts
│ │ │ │ ├── prop-types.ts
│ │ │ │ ├── props-list.ts
│ │ │ │ ├── props-map.ts
│ │ │ │ ├── props-transducer.ts
│ │ │ │ ├── reference.ts
│ │ │ │ ├── registered-setter.ts
│ │ │ │ ├── remote-component-description.ts
│ │ │ │ ├── resource-list.ts
│ │ │ │ ├── resource-type-config.ts
│ │ │ │ ├── resource-type.ts
│ │ │ │ ├── root-schema.ts
│ │ │ │ ├── scrollable.ts
│ │ │ │ ├── set-value-options.ts
│ │ │ │ ├── setter-config.ts
│ │ │ │ ├── setter-type.ts
│ │ │ │ ├── simulator-renderer.ts
│ │ │ │ ├── slot-schema.ts
│ │ │ │ ├── snippet.ts
│ │ │ │ ├── tip-config.ts
│ │ │ │ ├── tip-content.ts
│ │ │ │ ├── title-config.ts
│ │ │ │ ├── title-content.ts
│ │ │ │ ├── transformed-component-metadata.ts
│ │ │ │ ├── value-type.ts
│ │ │ │ ├── widget-base-config.ts
│ │ │ │ └── widget-config-area.ts
│ │ │ ├── shell-model-factory.ts
│ │ │ └── utils.ts
│ │ └── tsconfig.json
│ ├── utils/
│ │ ├── build.json
│ │ ├── build.test.json
│ │ ├── jest.config.js
│ │ ├── jest.setup.js
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── app-helper.ts
│ │ │ ├── asset.ts
│ │ │ ├── build-components.ts
│ │ │ ├── check-prop-types.ts
│ │ │ ├── check-types/
│ │ │ │ ├── index.ts
│ │ │ │ ├── is-action-content-object.ts
│ │ │ │ ├── is-basic-prop-type.ts
│ │ │ │ ├── is-component-schema.ts
│ │ │ │ ├── is-custom-view.ts
│ │ │ │ ├── is-dom-text.ts
│ │ │ │ ├── is-drag-any-object.ts
│ │ │ │ ├── is-drag-node-data-object.ts
│ │ │ │ ├── is-drag-node-object.ts
│ │ │ │ ├── is-dynamic-setter.ts
│ │ │ │ ├── is-function.ts
│ │ │ │ ├── is-i18n-data.ts
│ │ │ │ ├── is-isfunction.ts
│ │ │ │ ├── is-jsblock.ts
│ │ │ │ ├── is-jsexpression.ts
│ │ │ │ ├── is-jsslot.ts
│ │ │ │ ├── is-location-children-detail.ts
│ │ │ │ ├── is-location-data.ts
│ │ │ │ ├── is-lowcode-component-type.ts
│ │ │ │ ├── is-lowcode-project-schema.ts
│ │ │ │ ├── is-node-schema.ts
│ │ │ │ ├── is-node.ts
│ │ │ │ ├── is-object.ts
│ │ │ │ ├── is-procode-component-type.ts
│ │ │ │ ├── is-project-schema.ts
│ │ │ │ ├── is-required-prop-type.ts
│ │ │ │ ├── is-setter-config.ts
│ │ │ │ ├── is-setting-field.ts
│ │ │ │ └── is-title-config.ts
│ │ │ ├── clone-deep.ts
│ │ │ ├── clone-enumerable-property.ts
│ │ │ ├── context-menu.scss
│ │ │ ├── context-menu.tsx
│ │ │ ├── create-content.ts
│ │ │ ├── create-defer.ts
│ │ │ ├── create-icon.tsx
│ │ │ ├── css-helper.ts
│ │ │ ├── cursor.css
│ │ │ ├── cursor.ts
│ │ │ ├── env.ts
│ │ │ ├── get-prototype-of.ts
│ │ │ ├── has-own-property.ts
│ │ │ ├── index.ts
│ │ │ ├── is-css-url.ts
│ │ │ ├── is-element.ts
│ │ │ ├── is-es-module.ts
│ │ │ ├── is-form-event.ts
│ │ │ ├── is-function.ts
│ │ │ ├── is-object.ts
│ │ │ ├── is-plain-object.ts
│ │ │ ├── is-plugin-event-name.ts
│ │ │ ├── is-react.ts
│ │ │ ├── is-shaken.ts
│ │ │ ├── logger.ts
│ │ │ ├── misc.ts
│ │ │ ├── navtive-selection.ts
│ │ │ ├── node-helper.ts
│ │ │ ├── schema.ts
│ │ │ ├── script.ts
│ │ │ ├── set-prototype-of.ts
│ │ │ ├── shallow-equal.ts
│ │ │ ├── svg-icon.tsx
│ │ │ ├── transaction-manager.ts
│ │ │ ├── unique-id.ts
│ │ │ └── workspace.tsx
│ │ ├── test/
│ │ │ └── src/
│ │ │ ├── __snapshots__/
│ │ │ │ ├── is-react.test.tsx.snap
│ │ │ │ └── schema.test.ts.snap
│ │ │ ├── build-components/
│ │ │ │ ├── buildComponents.test.tsx
│ │ │ │ ├── getProjectUtils.test.ts
│ │ │ │ └── getSubComponent.test.ts
│ │ │ ├── check-prop-types.test.ts
│ │ │ ├── check-types/
│ │ │ │ ├── is-action-content-object.test.ts
│ │ │ │ ├── is-basic-prop-type.test.ts
│ │ │ │ ├── is-custom-view.test.tsx
│ │ │ │ ├── is-dom-text.test.ts
│ │ │ │ ├── is-drag-any-object.test.ts
│ │ │ │ ├── is-drag-node-data-object.test.ts
│ │ │ │ ├── is-drag-node-object.test.ts
│ │ │ │ ├── is-dynamic-setter.test.ts
│ │ │ │ ├── is-i18n-data.test.ts
│ │ │ │ ├── is-isfunction.test.ts
│ │ │ │ ├── is-jsblock.test.ts
│ │ │ │ ├── is-jsexpression.test.ts
│ │ │ │ ├── is-jsslot.test.ts
│ │ │ │ ├── is-location-children-detail.test.ts
│ │ │ │ ├── is-location-data.test.ts
│ │ │ │ ├── is-lowcode-component-type.test.ts
│ │ │ │ ├── is-lowcode-project-schema.test.ts
│ │ │ │ ├── is-node-schema.test.ts
│ │ │ │ ├── is-node.test.ts
│ │ │ │ ├── is-procode-component-type.test.ts
│ │ │ │ ├── is-project-schema.test.ts
│ │ │ │ ├── is-required-prop-type.test.ts
│ │ │ │ ├── is-setter-config.test.ts
│ │ │ │ ├── is-setting-field.test.ts
│ │ │ │ └── is-title-config.test.ts
│ │ │ ├── clone-deep.test.ts
│ │ │ ├── clone-enumerable-property.test.ts
│ │ │ ├── create-content.test.tsx
│ │ │ ├── create-defer.test.ts
│ │ │ ├── is-object.test.ts
│ │ │ ├── is-react.test.tsx
│ │ │ ├── is-shaken.test.ts
│ │ │ ├── misc.test.ts
│ │ │ ├── navtive-selection.test.ts
│ │ │ ├── schema.test.ts
│ │ │ ├── script.test.ts
│ │ │ ├── svg-icon.test.tsx
│ │ │ ├── transaction-manager.test.ts
│ │ │ └── unique-id.test.ts
│ │ └── tsconfig.json
│ └── workspace/
│ ├── build.json
│ ├── build.test.json
│ ├── jest.config.js
│ ├── package.json
│ ├── src/
│ │ ├── context/
│ │ │ ├── base-context.ts
│ │ │ └── view-context.ts
│ │ ├── index.ts
│ │ ├── inner-plugins/
│ │ │ └── webview.tsx
│ │ ├── layouts/
│ │ │ └── workbench.tsx
│ │ ├── less-variables.less
│ │ ├── resource-type.ts
│ │ ├── resource.ts
│ │ ├── skeleton-context.ts
│ │ ├── view/
│ │ │ ├── editor-view.tsx
│ │ │ ├── resource-view.less
│ │ │ ├── resource-view.tsx
│ │ │ └── window-view.tsx
│ │ ├── window.ts
│ │ └── workspace.ts
│ └── tsconfig.json
├── scripts/
│ ├── build.sh
│ ├── create.sh
│ ├── set-repo.js
│ ├── setup-for-test.sh
│ ├── setup-skip-build.sh
│ ├── setup.js
│ ├── setup.sh
│ ├── start-server.sh
│ ├── start.js
│ ├── start.sh
│ ├── sync-oss.js
│ ├── sync.sh
│ └── watchdog.js
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
quote_type = single
[*.md]
trim_trailing_whitespace = false
================================================
FILE: .eslintignore
================================================
# 忽略目录
node_modules
test-cases
test
output
build
dist
demo
es
lib
tests
.*
~*
# 忽略文件
**/*.min.js
**/*-min.js
**/*.bundle.js
================================================
FILE: .eslintrc.js
================================================
module.exports = {
extends: 'eslint-config-ali/typescript/react',
parserOptions: {
project: [], // for lint performance
createDefaultProgram: false, // for lint performance
},
rules: {
'react/no-multi-comp': 0,
'no-unused-expressions': 0,
'implicit-arrow-linebreak': 1,
'no-nested-ternary': 1,
'no-mixed-operators': 1,
'@typescript-eslint/ban-types': 1,
'no-shadow': 1,
'no-prototype-builtins': 1,
'no-useless-constructor': 1,
'no-empty-function': 1,
'lines-between-class-members': 0,
'no-await-in-loop': 0,
'no-plusplus': 0,
'@typescript-eslint/no-parameter-properties': 0,
'no-restricted-exports': ['error'],
'no-multi-assign': 1,
'no-dupe-class-members': 1,
'react/no-deprecated': 1,
'no-useless-escape': 1,
'brace-style': 1,
'@typescript-eslint/no-inferrable-types': 0,
'no-proto': 0,
'prefer-const': 0,
'eol-last': 0,
'react/no-find-dom-node': 0,
'no-case-declarations': 0,
'@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/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,
},
};
================================================
FILE: .github/CODEOWNERS
================================================
# ref: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence
* @liujuping @1ncounter
/modules/material-parser @akirakai
/modules/code-generator @qingniaotonghua
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: Bug report / 提交 bug
about: Create a report to help us improve / 提交一个好的 issue 帮助我们优化引擎,[引擎的 issue 说明](https://lowcode-engine.cn/site/community/issue)
title: ''
labels: ''
assignees: ''
---
## **Describe the bug (required)** / **详细描述 bug(必填)**
A clear and concise description of what the bug is. / 请提供清晰且精确的 bug 描述
---
## **To Reproduce (required)** / **如何复现 bug?(必填,非常重要)**
Steps to reproduce the behavior: / 详细复现步骤:
---
English version example:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
中文版示例:
1. 打开 [demo](http://lowcode-engine.cn/demo);
2. 点击标题;
3. 在右侧修改标题内容为「修改后的标题」;
4. 渲染画布标题组件没有更新显示为「修改后的标题」;
## **Expected behavior (required)** / **预期行为(必填,非常重要)**
A clear and concise description of what did you expect to happen. / 请清晰和精确的描述你预期的行为
---
## **Screenshots (optional)** / **bug 截图(可选)**
Sceenshots for further information. (If applicable.) / 一些有用的截图将会帮助我们更好的明确以及定位问题
---
## **Environments (please complete the following information) (required):** / **请提供如下信息(必填)**
- AliLowCodeEngine version: [e.g. 1.0.0] / 低代码引擎版本
- AliLowCodeEngineExt version: [e.g. 1.0.0] / 低代码引擎扩展包版本
- Browser [e.g. chrome, safari] / 浏览器版本
- materials / plugins / tools / 其他物料 / 插件 / 工具链版本
> (this information can be collected via [the manual plugin](https://img.alicdn.com/imgextra/i1/O1CN0115zonY1IsgbkZ2ir7_!!6000000000949-2-tps-3066-1650.png) / 版本信息可[通过低代码用户手册插件收集](https://img.alicdn.com/imgextra/i1/O1CN0115zonY1IsgbkZ2ir7_!!6000000000949-2-tps-3066-1650.png))
## **Additional context (optional)** / **更多额外信息(可选)**
Any other context of the problem here. / 可以追加更多的额外信息,帮助定位问题
================================================
FILE: .github/workflows/check base branch.yml
================================================
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 }}
================================================
FILE: .github/workflows/ci.yml
================================================
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
================================================
FILE: .github/workflows/cov packages.yml
================================================
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
================================================
FILE: .github/workflows/help wanted.yml
================================================
name: Help Wanted
on:
issues:
types: [labeled]
jobs:
reply-helper:
runs-on: ubuntu-latest
steps:
- name: help wanted
if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v2
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, PR wanted。
你好 @${{ github.event.issue.user.login }},我们完全同意你的提议/反馈,欢迎 PR。
================================================
FILE: .github/workflows/insufficient information.yml
================================================
name: Insufficient Info
on:
issues:
types: [labeled]
jobs:
reply-helper:
runs-on: ubuntu-latest
steps:
- name: insufficient information
if: github.event.label.name == 'insufficient information'
uses: actions-cool/issues-helper@v2
with:
actions: 'create-comment'
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) 补全信息,也可以通过阅读 [引擎的 issue 说明](https://lowcode-engine.cn/site/community/issue) 了解什么类型的 issue 可以获得更好、更快的支持。
================================================
FILE: .github/workflows/pr comment by chatgpt.yml
================================================
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 }}
================================================
FILE: .github/workflows/pre build.yml
================================================
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
================================================
FILE: .github/workflows/publish docs.yml
================================================
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 }}'
})
================================================
FILE: .github/workflows/publish engine beta.yml
================================================
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
================================================
FILE: .github/workflows/publish engine.yml
================================================
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
================================================
FILE: .github/workflows/stale.yml
================================================
name: 'Close stale issues and PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v4
with:
stale-issue-message: 'This issue is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 2 days.'
stale-pr-message: 'This PR is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 2 days.'
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: 10
days-before-pr-stale: 10
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'
exempt-all-assignee: true
================================================
FILE: .github/workflows/test modules.yml
================================================
name: Lint & Test (Mods)
on:
push:
paths:
- 'modules/**'
- '!modules/**.md'
pull_request:
paths:
- 'modules/**'
- '!modules/**.md'
jobs:
lint:
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
- name: lint
run: npm run lint:modules
test-code-generator:
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 modules/code-generator && npm i && npm run build && npm test
================================================
FILE: .github/workflows/test packages.yml
================================================
name: Lint & Test (Pkgs)
on:
push:
paths:
- 'packages/**'
- '!packages/**.md'
pull_request:
paths:
- 'packages/**'
- '!packages/**.md'
jobs:
lint:
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: lint
run: npm run lint
test-designer:
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/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
================================================
FILE: .gitignore
================================================
# project custom
build
dist
packages/*/lib/
packages/*/es/
packages/*/dist/
packages/*/output/
packages/demo/
package-lock.json
yarn.lock
pnpm-lock.yaml
deploy-space/packages
deploy-space/.env
# IDE
.vscode
.idea
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
coverage-all
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
lib
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# mac config files
.DS_Store
# codealike
codealike.json
.node
.must.config.js
================================================
FILE: .prettierrc.js
================================================
module.exports = {
printWidth: 100,
tabWidth: 2,
semi: true,
singleQuote: true,
trailingComma: 'all',
};
================================================
FILE: .stylelintignore
================================================
# 忽略目录
node_modules/
build/
dist/
# 忽略文件
**/*.min.css
**/*-min.css
**/*.bundle.css
================================================
FILE: .stylelintrc.js
================================================
module.exports = {
extends: 'stylelint-config-ali',
rules: {
"selector-max-id": 2
}
};
================================================
FILE: CONTRIBUTOR.md
================================================
十分感谢参与贡献过低代码引擎的小伙伴们,下面名单按字母排序:
- [albertxiao1994](https://github.com/albertxiao1994)
- [alex-mm](https://github.com/alex-mm)
- [alvarto](https://github.com/alvarto)
- [alvinhui](https://github.com/alvinhui)
- [boycgit](https://github.com/boycgit)
- [chenmingjia](https://github.com/chenmingjia)
- [Clarence-pan](https://github.com/Clarence-pan)
- [hujiulong](https://github.com/hujiulong)
- [hzd822](https://github.com/hzd822)
- [JackLian](https://github.com/JackLian)
- [jayjliang](https://github.com/jayjliang)
- [Jeffery-Young](https://github.com/Jeffery-Young)
- [jinggk](https://github.com/jinggk)
- [junlonghuo](https://github.com/junlonghuo)
- [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)
- [yanbingbing](https://github.com/yanbingbing)
- [Ychangqing](https://github.com/Ychangqing)
- [yize](https://github.com/yize)
- [youluna](https://github.com/youluna)
- [ibreathebsb](https://github.com/ibreathebsb)
如果您贡献过低代码引擎,但是没有看到您的名字,为我们的疏忽感到抱歉。欢迎您通过 PR 补充上自己的名字。
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Alibaba
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: abc.json
================================================
{
"name": "lowcode-engine",
"assets": {
"type": "command",
"command": {
"cmd": [
"./scripts/deploy.sh $BUILD_DEST"
]
}
}
}
================================================
FILE: babel.config.js
================================================
module.exports = {
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
[require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }],
],
};
================================================
FILE: commitlint.config.js
================================================
module.exports = {
extends: ['ali'],
};
================================================
FILE: deploy-space/lerna.json
================================================
{
"version": "independent",
"npmClient": "yarn",
"registry": "http://registry.npm.alibaba-inc.com",
"useWorkspaces": true,
"packages": [
"packages/*"
]
}
================================================
FILE: deploy-space/package.json
================================================
{
"private": true,
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": [
"**/css-modules-typescript-loader",
"**/@alife/theme-lowcode-*"
]
},
"dependencies": {
"tslib": "^1.11.1",
"typescript": "^3.8.3"
}
}
================================================
FILE: deploy-space/static/index.html
================================================
LowCodeEngine Editor DEMO
================================================
FILE: deploy-space/static/preview.html
================================================
LowCodeEngine Editor DEMO
================================================
FILE: deploy-space/tsconfig.json
================================================
{
"compilerOptions": {
"declaration": false,
"lib": ["es2015", "dom"],
// Target latest version of ECMAScript.
"target": "esnext",
// Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
"module": "esnext",
// Search under node_modules for non-relative imports.
"moduleResolution": "node",
// Process & infer types from .js files.
"allowJs": true,
// Report errors in .js files.
"checkJs": false,
// Don't emit; allow Babel to transform files.
// "noEmit": true,
// Enable strictest settings like strictNullChecks & noImplicitAny.
"strict": false,
// Allow default imports from modules with no default export. This does not affect code emit, just typechecking.
"allowSyntheticDefaultImports": true,
// Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'.
"esModuleInterop": true,
// Specify JSX code generation: 'preserve', 'react-native', or 'react'.
"jsx": "preserve",
// Import emit helpers (e.g. __extends, __rest, etc..) from tslib
"importHelpers": true,
// Enables experimental support for ES7 decorators.
"experimentalDecorators": true,
// Generates corresponding .map file.
"sourceMap": false,
// Disallow inconsistently-cased references to the same file.
"forceConsistentCasingInFileNames": true,
// Allow json import
"resolveJsonModule": true,
// skip type checking of declaration files
"skipLibCheck": true,
"outDir": "lib"
},
"exclude": ["**/test", "**/lib", "**/es", "node_modules"]
}
================================================
FILE: docs/.gitignore
================================================
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
================================================
FILE: docs/README.md
================================================
# Low-Code Engine 文档中心(site)
This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator.
### 安装
```
$ yarn
```
### 本地开发
```
$ yarn start
```
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
### 构建
```
$ yarn build
```
### 部署
```bash
1. npm run build
2. npm publish # 记得改下版本号,比如 1.0.1
# 发布完后执行 tnpm syncOss 同步到 uipaas CDN
3. tnpm syncOss
4. 更新 diamond 版本 1.0.1
5. lowcode-engine.cn 站点生效
```
## 功能
- [x] 支持本地离线搜搜
- [x] 版本化文档管理
- [x] 离线静态部署
- [x] 主题(fork 宜搭开发者中心)
## 使用文档
https://docusaurus.io/zh-CN/docs/docs-introduction
================================================
FILE: docs/babel.config.js
================================================
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
================================================
FILE: docs/community/issue.md
================================================
---
title: 关于引擎的 issue 说明
sidebar_position: 2
---
> 提交地址:[https://github.com/alibaba/lowcode-engine/issues](https://github.com/alibaba/lowcode-engine/issues)
### 提交前必读
由于引擎项目复杂,很多问题在复现和沟通上无法花费太多时间,需要大家尽力将复现步骤说明白。

**你以为的 issue**

**我们看到的 issue**
为了更好的进行协作,对引擎 issue 的处理定了一些处理的优先级。请大家认真阅读 Orz.
- 【支持快】通过线上 Demo 地址 + 控制台输入 API 可复现。
- 【支持快】通过线上 Demo + 导入 schema 可复现
- 【支持稍慢】通过线上 Demo + 完整操作步骤可复现
- 【支持稍慢】通过线上 Demo + 变更代码可复现,并清楚的说明变更代码的位置和内容
- 【支持慢】有完整的项目地址,下载下来可直接安装依赖并启动复现的
- 【支持慢】需求类型的由于人力有限,欢迎大家 PR,如能讲清楚背景上下文和场景,项目维护团队更容易给出方案建议或方向指引。
- 【不保证提供支持】其他
- 只有标题没有复现步骤
- 复现步骤不清晰
- 和引擎无关的
### 不同优先级的示例
#### 【支持快】通过线上 Demo 地址 + 控制台输入 API 可复现。
**示例**

复现步骤:
- 打开线上 demo
- 在控制台输入
```json
// 当前 doc
const doc = window.AliLowCodeEngine.project.currentDocument
// 新建 doc 并成功切换
window.AliLowCodeEngine.project.openDocument({
componentName: 'Page'
});
// 无法切换回来
window.AliLowCodeEngine.project.openDocument('docl4xkca5b')
```
预期效果:
- 使用 openDocument 可以正常的切换回原来的 doc
#### 【支持快】通过线上 demo + 导入 schema 可复现
步骤:
- 使用线上 demo
- 导入下面的 schema
- schema 代码/schema zip 压缩包
- 页面效果如下
期望:
- 页面中的 xxx 部分和预期不符合,期望的效果是 xxx
#### 【支持稍慢】通过线上 demo + 完整操作步骤可复现
**示例**
1.使用 antd 组件

2.拖拽这个组件

3.配置该属性值为 100

期望效果:
- 组件同配置一致
#### 【支持稍慢】通过线上 demo + 变更代码可复现,并清楚的说明变更代码的位置和内容
**示例**




#### 【支持慢】有完整的项目地址,下载下来可直接安装依赖并启动复现的
由于完整的项目中有很多冗余的信息,这部分排查起来十分耗时且困难。不推荐使用改方式。
#### 【不保证提供支持】其他
##### 只有标题没有复现步骤

##### 复现步骤不清晰

##### 和引擎无关的

### 扩展阅读
强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。(此段参考 [antd](https://github.com/ant-design/ant-design))
================================================
FILE: docs/config/navbar.js
================================================
/**
* 此配置的修改,如未生效,可以重新启动下即可
*/
module.exports = {
title: '',
logo: {
alt: 'LowCode-Engine',
src: 'https://img.alicdn.com/imgextra/i2/O1CN01uv6vu822RBCSYLro2_!!6000000007116-55-tps-139-26.svg',
srcDark: 'https://tianshu.alicdn.com/052a190e-c961-4afe-aa4c-49ee9722952d.svg',
},
items: [
{
type: 'doc',
docId: 'guide/quickStart/intro',
position: 'left',
label: '文档',
},
{
type: 'doc',
docId: 'api/index',
position: 'left',
label: 'API',
},
{
type: 'doc',
docId: 'specs/lowcode-spec',
position: 'left',
label: '协议',
},
{
type: 'doc',
docId: 'faq/index',
position: 'left',
label: 'FAQ',
},
{
type: 'doc',
docId: 'article/index',
position: 'left',
label: '文章',
},
{
type: 'doc',
docId: 'video/index',
position: 'left',
label: '视频',
},
{
type: 'doc',
docId: 'demoUsage/intro',
position: 'left',
label: 'Demo 使用文档',
},
{
to: '/community/issue',
position: 'left',
label: '社区',
activeBaseRegex: '/community/',
},
// 版本切换,如需,这里开启即可
// {
// type: 'docsVersionDropdown',
// position: 'right',
// dropdownActiveClassDisabled: true,
// },
// {
{
href: 'https://github.com/alibaba/lowcode-engine',
position: 'right',
className: 'header-github-link',
'aria-label': 'GitHub repository',
},
{
type: 'doc',
docId: 'participate/index',
position: 'right',
label: '参与贡献',
},
{
type: 'search',
position: 'right',
},
],
};
================================================
FILE: docs/config/sidebars.js
================================================
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const getDocsFromDir = require('../scripts/getDocsFromDir');
module.exports = {
// 手动配置的导航
// guide: [
// 'guide/quickStart/intro',
// 'guide/quickStart/start',
// {
// type: 'category',
// label: 'FAQ',
// collapsed: false,
// items: getDocsFromDir('guide/quickStart/faq'),
// },
// ],
/**
* 根据当前目录自动生成导航配置
*/
guide: [
[
{
type: 'category',
label: '入门',
collapsed: false,
items: getDocsFromDir('guide/quickStart'),
},
{
type: 'category',
label: '创建编辑器',
collapsed: false,
items: getDocsFromDir('guide/create'),
},
{
type: 'category',
label: '扩展编辑器',
collapsed: false,
items: getDocsFromDir('guide/expand/editor', [{ dir: 'guide/expand/editor/parts', label: 'Parts·造物' }]),
},
{
type: 'category',
label: '扩展运行时',
collapsed: false,
items: getDocsFromDir('guide/expand/runtime'),
},
{
type: 'category',
label: '设计原理',
collapsed: false,
items: getDocsFromDir('guide/design'),
},
{
type: 'category',
label: '附录',
collapsed: false,
items: [
{
type: 'link',
label: '更新日志',
href: 'https://github.com/alibaba/lowcode-engine/releases',
},
...getDocsFromDir('guide/appendix'),
{
type: 'category',
label: '预置设置器详情',
items: getDocsFromDir('guide/appendix/setterDetails'),
},
],
},
{
type: 'link',
label: '技术白皮书',
href: 'https://developer.aliyun.com/ebook/7507',
},
],
],
api: [
{
type: 'autogenerated',
dirName: 'api',
},
],
specs: [
{
type: 'autogenerated',
dirName: 'specs',
},
],
faq: [
{
type: 'autogenerated',
dirName: 'faq',
},
],
participate: [
{
type: 'autogenerated',
dirName: 'participate',
},
],
demoUsage: [
{
type: 'autogenerated',
dirName: 'demoUsage',
},
],
};
================================================
FILE: docs/config/sidebarsCommunity.js
================================================
module.exports = {
community: [
{
type: 'autogenerated',
dirName: '.',
},
{
type: 'link',
label: '生态资源',
href: 'https://github.com/lowcode-workspace/awesome-lowcode-engine',
},
],
};
================================================
FILE: docs/docs/api/canvas.md
================================================
---
title: canvas - 画布 API
sidebar_position: 10
---
> **@types** [IPublicApiCanvas](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/canvas.ts)
> **@since** v1.1.0
## 模块简介
通过该模块可以触达对画布拖拽相关的一些能力。
## 变量
### dragon
获取拖拽操作对象的实例
`@type {IPublicModelDragon | null}`
相关类型:[IPublicModelDragon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/dragon.ts)
### activeTracker
获取活动追踪器实例
`@type {IPublicModelActiveTracker | null}`
相关类型:[IPublicModelActiveTracker](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/active-tracker.ts)
### isInLiveEditing
是否处于 LiveEditing 状态
`@type {boolean}`
### clipboard
全局剪贴板实例
`@type {IPublicModelClipboard}`
相关类型:[IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)
## 方法
### createLocation
创建一个文档插入位置对象,该对象用来描述一个即将插入的节点在文档中的位置
```typescript
/**
* 创建一个文档插入位置对象,该对象用来描述一个即将插入的节点在文档中的位置
* create a drop location for document, drop location describes a location in document
* @since v1.1.0
*/
createLocation(locationData: IPublicTypeLocationData): IPublicModelDropLocation;
```
### createScroller
创建一个滚动控制器 Scroller,赋予一个视图滚动的基本能力,
```typescript
/**
* 创建一个滚动控制器 Scroller,赋予一个视图滚动的基本能力,
* a Scroller is a controller that gives a view (IPublicTypeScrollable) the ability scrolling
* to some cordination by api scrollTo.
*
* when a scroller is inited, will need to pass is a scrollable, which has a scrollTarget.
* and when scrollTo(options: { left?: number; top?: number }) is called, scroller will
* move scrollTarget`s top-left corner to (options.left, options.top) that passed in.
* @since v1.1.0
*/
createScroller(scrollable: IPublicTypeScrollable): IPublicModelScroller;
```
### createScrollTarget
创建一个 ScrollTarget,与 Scroller 一起发挥作用,详见 [createScroller](#createscroller) 中的描述
```typescript
/**
* 创建一个 ScrollTarget,与 Scroller 一起发挥作用,详见 createScroller 中的描述
* this works with Scroller, refer to createScroller`s description
* @since v1.1.0
*/
createScrollTarget(shell: HTMLDivElement): IPublicModelScrollTarget;
```
================================================
FILE: docs/docs/api/command.md
================================================
---
title: command - 指令 API
sidebar_position: 10
---
## 模块概览
该模块使得与命令系统的交互成为可能,提供了一种全面的方式来处理、执行和管理应用程序中的命令。
## 接口
### IPublicApiCommand
与命令交互的接口。它提供了注册、注销、执行和管理命令的方法。
## 方法
### registerCommand
注册一个新命令及其处理函数。
```
typescriptCopy code
/**
* 注册一个新的命令及其处理程序。
* @param command {IPublicTypeCommand} - 要注册的命令。
*/
registerCommand(command: IPublicTypeCommand): void;
```
### unregisterCommand
注销一个已存在的命令。
```
typescriptCopy code
/**
* 注销一个已存在的命令。
* @param name {string} - 要注销的命令的名称。
*/
unregisterCommand(name: string): void;
```
### executeCommand
根据名称和提供的参数执行命令,确保参数符合命令的定义。
```
typescriptCopy code
/**
* 根据名称和提供的参数执行命令。
* @param name {string} - 要执行的命令的名称。
* @param args {IPublicTypeCommandHandlerArgs} - 命令的参数。
*/
executeCommand(name: string, args?: IPublicTypeCommandHandlerArgs): void;
```
### batchExecuteCommand
批量执行命令,在所有命令执行后进行重绘,历史记录中只记录一次。
```
typescriptCopy code
/**
* 批量执行命令,随后进行重绘,历史记录中只记录一次。
* @param commands {Array} - 命令对象的数组,包含名称和可选参数。
*/
batchExecuteCommand(commands: { name: string; args?: IPublicTypeCommandHandlerArgs }[]): void;
```
### listCommands
列出所有已注册的命令。
```
typescriptCopy code
/**
* 列出所有已注册的命令。
* @returns {IPublicTypeListCommand[]} - 已注册命令的数组。
*/
listCommands(): IPublicTypeListCommand[];
```
### onCommandError
为命令执行过程中的错误注册错误处理回调函数。
```
typescriptCopy code
/**
* 为命令执行过程中的错误注册一个回调函数。
* @param callback {(name: string, error: Error) => void} - 错误处理的回调函数。
*/
onCommandError(callback: (name: string, error: Error) => void): void;
```
================================================
FILE: docs/docs/api/common.md
================================================
---
title: common - 通用 API
sidebar_position: 10
---
> **@types** [IPublicApiCommon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/common.ts)
> **@since** v1.0.0
## 模块简介
通用模块里包含除了几大核心模块 API 之外的所有 API,比如通用 utils、面板扩展相关 等。
> 高能预警:之所以叫 skeletonCabin / designerCabin 跟兼容上一个版本的引擎有关系。若有必要,后面将用更有意义的命名空间来组织这些 API。
## 变量
#### utils
通用 utils,详见下方方法签名
相关类型:[IPublicApiCommonUtils](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/common.ts)
#### skeletonCabin
面板扩展相关,详见下方方法签名
## 方法
### utils
#### isNodeSchema
是否为合法的 schema 结构
```typscript
/**
* 是否为合法的 schema 结构
* check if data is valid NodeSchema
*
* @param {*} data
* @returns {boolean}
*/
isNodeSchema(data: any): boolean;
```
#### isFormEvent
是否为表单事件类型
```typescript
/**
* 是否为表单事件类型
* check if e is a form event
* @param {(KeyboardEvent | MouseEvent)} e
* @returns {boolean}
*/
isFormEvent(e: KeyboardEvent | MouseEvent): boolean;
```
#### getNodeSchemaById
从 schema 结构中查找指定 id 节点
```typescript
/**
* 从 schema 结构中查找指定 id 节点
* get node schema from a larger schema with node id
* @param {IPublicTypeNodeSchema} schema
* @param {string} nodeId
* @returns {(IPublicTypeNodeSchema | undefined)}
*/
getNodeSchemaById(
schema: IPublicTypeNodeSchema,
nodeId: string,
): IPublicTypeNodeSchema | undefined;
```
相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
#### executeTransaction
批处理事务,用于优化特定场景的性能
```typescript
/**
* 批处理事务,用于优化特定场景的性能
* excute something in a transaction for performence
*
* @param {() => void} fn
* @param {IPublicEnumTransitionType} type
* @since v1.0.16
*/
executeTransaction(fn: () => void, type: IPublicEnumTransitionType): void;
```
**@since v1.0.16**
**示例**
```typescript
import { common } from '@alilc/lowcode-engine';
import { IPublicEnumTransitionType } from '@alilc/lowcode-types';
common.utils.startTransaction(() => {
node1.setProps();
node2.setProps();
node3.setProps();
// ...
}, IPublicEnumTransitionType.repaint);
```
#### getConvertedExtraKey
props key 转化工具
```typescript
getConvertedExtraKey(key: string): string
```
**@since v1.0.17**
#### createIntl
i18n 相关工具
```typescript
/**
* i18n 相关工具
* i18n tools
*
* @param {(string | object)} instance
* @returns {{
* intlNode(id: string, params?: object): ReactNode;
* intl(id: string, params?: object): string;
* getLocale(): string;
* setLocale(locale: string): void;
* }}
* @since v1.0.17
*/
createIntl(instance: string | object): {
intlNode(id: string, params?: object): ReactNode;
intl(id: string, params?: object): string;
getLocale(): string;
setLocale(locale: string): void;
};
```
**@since v1.0.17**
**示例**
```typescript
import { common } from '@alilc/lowcode-engine';
import enUS from './en-US.json';
import zhCN from './zh-CN.json';
const { intl, getLocale, setLocale } = common.utils.createIntl({
'en-US': enUS,
'zh-CN': zhCN,
});
```
#### intl
i18n 转换方法
```typescript
/**
* i18n 转换方法
*/
intl(data: IPublicTypeI18nData | string, params?: object): string;
```
**示例**
```
const title = common.utils.intl(node.title)
```
### skeletonCabin
#### Workbench
编辑器框架 View
```typescript
/**
* 编辑器框架 View
* get Workbench Component
*/
get Workbench(): Component;
```
================================================
FILE: docs/docs/api/commonUI.md
================================================
---
title: commonUI - UI 组件库
sidebar_position: 10
---
## 简介
CommonUI API 是一个专为低代码引擎设计的组件 UI 库,使用它开发的插件,可以保证在不同项目和主题切换中能够保持一致性和兼容性。
## 组件列表
### Tip
提示组件
| 参数 | 说明 | 类型 | 默认值 |
|-----------|--------------|---------------------------------------|--------|
| className | className | string (optional) | |
| children | tip 的内容 | IPublicTypeI18nData \| ReactNode | |
| direction | tip 的方向 | 'top' \| 'bottom' \| 'left' \| 'right' | |
### HelpTip
带 help icon 的提示组件
| 参数 | 说明 | 类型 | 默认值 |
|-----------|--------|-----------------------------------|--------|
| help | 描述 | IPublicTypeHelpTipConfig | |
| direction | 方向 | IPublicTypeTipConfig['direction'] | 'top' |
| size | 方向 | IconProps['size'] | 'small'|
### Title
标题组件
| 参数 | 说明 | 类型 | 默认值 |
|-----------|------------|-----------------------------|--------|
| title | 标题内容 | IPublicTypeTitleContent | |
| className | className | string (optional) | |
| onClick | 点击事件 | () => void (optional) | |
### ContextMenu
| 参数 | 说明 | 类型 | 默认值 |
|--------|----------------------------------------------------|------------------------------------|--------|
| menus | 定义上下文菜单的动作数组 | IPublicTypeContextMenuAction[] | |
| children | 组件的子元素 | React.ReactElement[] | |
**IPublicTypeContextMenuAction Interface**
| 参数 | 说明 | 类型 | 默认值 |
|------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|----------------------------------------|
| name | 动作的唯一标识符
Unique identifier for the action | string | |
| title | 显示的标题,可以是字符串或国际化数据
Display title, can be a string or internationalized data | string \| IPublicTypeI18nData (optional) | |
| type | 菜单项类型
Menu item type | IPublicEnumContextMenuType (optional) | IPublicEnumContextMenuType.MENU_ITEM |
| action | 点击时执行的动作,可选
Action to execute on click, optional | (nodes: IPublicModelNode[]) => void (optional) | |
| items | 子菜单项或生成子节点的函数,可选,仅支持两级
Sub-menu items or function to generate child node, optional | Omit[] \| ((nodes: IPublicModelNode[]) => Omit[]) (optional) | |
| condition | 显示条件函数
Function to determine display condition | (nodes: IPublicModelNode[]) => boolean (optional) | |
| disabled | 禁用条件函数,可选
Function to determine disabled condition, optional | (nodes: IPublicModelNode[]) => boolean (optional) | |
**ContextMenu 示例**
```typescript
const App = () => {
const menuItems: IPublicTypeContextMenuAction[] = [
{
name: 'a',
title: '选项 1',
action: () => console.log('选项 1 被点击'),
},
{
name: 'b',
title: '选项 2',
action: () => console.log('选项 2 被点击'),
},
];
const ContextMenu = ctx.commonUI.ContextMenu;
return (
);
};
export default App;
```
**ContextMenu.create 示例**
```typescript
const App = () => {
const menuItems: IPublicTypeContextMenuAction[] = [
{
name: 'a',
title: '选项 1',
action: () => console.log('选项 1 被点击'),
},
{
name: 'b',
title: '选项 2',
action: () => console.log('选项 2 被点击'),
},
];
const ContextMenu = ctx.commonUI.ContextMenu;
return (
{
ContextMenu.create(menuItems, e);
}}>点击这里
);
};
export default App;
```
### Balloon
详细文档: [Balloon Documentation](https://fusion.design/pc/component/balloon)
### Breadcrumb
详细文档: [Breadcrumb Documentation](https://fusion.design/pc/component/breadcrumb)
### Button
详细文档: [Button Documentation](https://fusion.design/pc/component/button)
### Card
详细文档:[Card Documentation](https://fusion.design/pc/component/card)
### Checkbox
详细文档:[Checkbox Documentation](https://fusion.design/pc/component/checkbox)
### DatePicker
详细文档:[DatePicker Documentation](https://fusion.design/pc/component/datepicker)
### Dialog
详细文档:[Dialog Documentation](https://fusion.design/pc/component/dialog)
### Dropdown
详细文档:[Dropdown Documentation](https://fusion.design/pc/component/dropdown)
### Form
详细文档:[Form Documentation](https://fusion.design/pc/component/form)
### Icon
详细文档:[Icon Documentation](https://fusion.design/pc/component/icon)
引擎默认主题支持的 icon 列表:https://fusion.design/64063/component/icon?themeid=20133
### Input
详细文档:[Input Documentation](https://fusion.design/pc/component/input)
### Loading
详细文档:[Loading Documentation](https://fusion.design/pc/component/loading)
### Message
详细文档:[Message Documentation](https://fusion.design/pc/component/message)
### Overlay
详细文档:[Overlay Documentation](https://fusion.design/pc/component/overlay)
### Pagination
详细文档:[Pagination Documentation](https://fusion.design/pc/component/pagination)
### Radio
详细文档:[Radio Documentation](https://fusion.design/pc/component/radio)
### Search
详细文档:[Search Documentation](https://fusion.design/pc/component/search)
### Select
详细文档:[Select Documentation](https://fusion.design/pc/component/select)
### SplitButton
详细文档:[SplitButton Documentation](https://fusion.design/pc/component/splitbutton)
### Step
详细文档:[Step Documentation](https://fusion.design/pc/component/step)
### Switch
详细文档:[Switch Documentation](https://fusion.design/pc/component/switch)
### Tab
详细文档:[Tab Documentation](https://fusion.design/pc/component/tab)
### Table
详细文档:[Table Documentation](https://fusion.design/pc/component/table)
### Tree
详细文档:[Tree Documentation](https://fusion.design/pc/component/tree)
### TreeSelect
详细文档:[TreeSelect Documentation](https://fusion.design/pc/component/treeselect)
### Upload
详细文档:[Upload Documentation](https://fusion.design/pc/component/upload)
### Divider
详细文档:[Divider Documentation](https://fusion.design/pc/component/divider)
## 说明
如果需要其他组件,可以提 issue 给我们。
================================================
FILE: docs/docs/api/config.md
================================================
---
title: config - 配置 API
sidebar_position: 5
---
> **@types** [IPublicModelEngineConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/engine-config.ts)
> **@since** v1.0.0
## 模块简介
配置模块,负责配置的读、写等操作。
## 方法
### get
获取指定 key 的值
```typescript
/**
* 获取指定 key 的值
* get value by key
* @param key
* @param defaultValue
* @returns
*/
get(key: string, defaultValue?: any): any;
```
**示例**
```typescript
import { config } from '@alilc/lowcode-engine';
config.get('keyA', true);
config.get('keyB', { a: 1 });
```
### set
设置指定 key 的值
```typescript
/**
* 设置指定 key 的值
* set value for certain key
* @param key
* @param value
*/
set(key: string, value: any): void;
```
**示例**
```typescript
import { config } from '@alilc/lowcode-engine';
config.set('keyC', 1);
```
### has
判断指定 key 是否有值
```typescript
/**
* 判断指定 key 是否有值
* check if config has certain key configed
* @param key
* @returns
*/
has(key: string): boolean;
```
**示例**
```typescript
import { config } from '@alilc/lowcode-engine';
config.has('keyD');
```
### setConfig
批量设值,set 的对象版本
```typescript
/**
* 批量设值,set 的对象版本
* set multiple config key-values
* @param config
*/
setConfig(config: { [key: string]: any }): void;
```
**示例**
```typescript
import { config } from '@alilc/lowcode-engine';
config.setConfig({ keyA: false, keyB: 2 });
```
### getPreference
获取全局 Preference 管理器,用于管理全局浏览器侧用户 Preference,如 Panel 是否钉住
```typescript
/**
* 获取全局 Preference, 用于管理全局浏览器侧用户 Preference,如 Panel 是否钉住
* get global user preference manager, which can be use to store
* user`s preference in user localstorage, such as a panel is pinned or not.
* @returns {IPublicModelPreference}
* @since v1.1.0
*/
getPreference(): IPublicModelPreference;
```
相关类型:[IPublicModelPreference](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/preference.ts)
**@since v1.1.0**
示例
```javascript
import { config } from '@alilc/lowcode-engine';
const panelName = 'outline-master-pane';
// 设置大纲树面板钉住,在大纲树下次重新打开时生效
config.getPreference().set(`${panelName}-pinned-status-isFloat`, false, 'skeleton')
```
## 事件
### onceGot
获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值
注:此函数返回 Promise 实例
```typescript
/**
* 获取指定 key 的值,若此时还未赋值,则等待,若已有值,则直接返回值
* 注:此函数返回 Promise 实例,只会执行(fullfill)一次
* wait until value of certain key is set, will only be
* triggered once.
* @param key
* @returns
*/
onceGot(key: string): Promise;
```
**示例**
```typescript
import { config } from '@alilc/lowcode-engine';
config.onceGot('keyA').then(value => {
console.log(`The value of keyA is ${value}`);
});
// or
const value = await config.onceGot('keyA');
```
### onGot
获取指定 key 的值,函数回调模式,若多次被赋值,回调会被多次调用
```typescript
/**
* 获取指定 key 的值,函数回调模式,若多次被赋值,回调会被多次调用
* set callback for event of value set for some key
* this will be called each time the value is set
* @param key
* @param fn
* @returns
*/
onGot(key: string, fn: (data: any) => void): () => void;
```
**示例**
```typescript
import { config } from '@alilc/lowcode-engine';
config.onGot('keyA', (value) => {
console.log(`The value of keyA is ${value}`);
});
const.set('keyA', 1); // 'The value of keyA is 1'
const.set('keyA', 2); // 'The value of keyA is 2'
```
================================================
FILE: docs/docs/api/configOptions.md
================================================
---
title: config options - 配置列表
sidebar_position: 5
---
> **@types** [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts)
## 配置方式
#### init API
```javascript
import { init } from '@alilc/lowcode-engine';
init(document.getElementById('engine'), {
enableCondition: false,
});
```
[**init api**](./init)
#### config API
```javascript
import { config } from '@alilc/lowcode-engine';
config.set('enableCondition', false)
```
[**config api**](./config)
## 配置详情
> 源码详见 [IPublicTypeEngineOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/engine-options.ts)
### 画布
#### locale - 语言
`@type {string}`、`@default {zh-CN}`
语言
#### device - 设备类型
`@type {string}`
引擎默认支持的 device 类型有 `default`、`mobile`、`iphonex`、`iphone6`。
插件 `@alilc/lowcode-plugin-simulator-select` 支持的 device 类型有 `default`、`phone`、`tablet`、`desktop`。
如果需要自定义的 device 类型,需要补充 device 类型对应的样式,例如 device 为 phone 时,需要补充样式如下:
```css
.lc-simulator-device-phone {
top: 16px;
bottom: 16px;
left: 50%;
width: 375px;
transform: translateX(-50%);
margin: auto;
}
```
#### deviceClassName
`@type {string}`
指定初始化的 deviceClassName,挂载到画布的顶层节点上
#### appHelper
与 react-renderer 的 appHelper 一致,https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper
#### enableCondition
`@type {boolean}`
是否开启 condition 的能力,默认在设计器中不管 condition 是啥都正常展示
#### disableAutoRender
`@type {boolean}` `@default {false}`
关闭画布自动渲染,在资产包多重异步加载的场景有效
#### renderEnv - 渲染器类型
渲染器类型
`@type {string}`、`@default {react}`
#### simulatorUrl
`@type {string[]}`
设置 simulator 相关的 url
#### enableStrictNotFoundMode
`@type {boolean}` `@default {false}`
当开启组件未找到严格模式时,渲染模块不会默认给一个容器组件
### 编排
#### focusNodeSelector - 指定根组件
配置指定节点为根组件
类型定义
```typescript
focusNodeSelector?: (rootNode: IPublicModelNode) => Node;
```
#### supportVariableGlobally - 全局变量配置
`@type {boolean}` `@default {false}`
设置所有属性支持变量配置
开启拖拽组件时,即将被放入的容器是否有视觉反馈
#### customizeIgnoreSelectors - 点击忽略
配置画布中,需要屏蔽点击事件的元素,即配置的元素默认点击行为均不生效。
类型定义:
```typescript
customizeIgnoreSelectors?: (defaultIgnoreSelectors: string[], e: MouseEvent) => string[];
```
默认值:
```javascript
() => {
return [
'.next-input-group',
'.next-checkbox-group',
'.next-checkbox-wrapper',
'.next-date-picker',
'.next-input',
'.next-month-picker',
'.next-number-picker',
'.next-radio-group',
'.next-range',
'.next-range-picker',
'.next-rating',
'.next-select',
'.next-switch',
'.next-time-picker',
'.next-upload',
'.next-year-picker',
'.next-breadcrumb-item',
'.next-calendar-header',
'.next-calendar-table',
'.editor-container', // 富文本组件
]
}
```
#### enableCanvasLock
`@type {boolean}` `@default {false}`
打开画布的锁定操作
#### enableLockedNodeSetting
`@type {boolean}` `@default {false}`
容器锁定后,容器本身是否可以设置属性,仅当画布锁定特性开启时生效
#### enableMouseEventPropagationInCanvas
`@type {boolean}` `@default {false}`
鼠标事件(mouseover、mouseleave、mousemove)在画布中是否允许冒泡,默认不允许。
#### enableReactiveContainer
`@type {boolean}` `@default {false}`
#### enableContextMenu - 开启右键菜单
`@type {boolean}` `@default {false}`
是否开启右键菜单
#### disableDetecting
`@type {boolean}` `@default {false}`
关闭拖拽组件时的虚线响应,性能考虑
#### disableDefaultSettingPanel
`@type {boolean}` `@default {false}`
禁止默认的设置面板
#### disableDefaultSetters
`@type {boolean}` `@default {false}`
禁止默认的设置器
#### stayOnTheSameSettingTab
`@type {boolean}` `@default {false}`
当选中节点切换时,是否停留在相同的设置 tab 上
#### hideSettingsTabsWhenOnlyOneItem
`@type {boolean}` `@default {false}`
是否在只有一个 item 的时候隐藏设置 tabs
#### hideComponentAction
`@type {boolean}` `@default {false}`
隐藏设计器辅助层
#### thisRequiredInJSE
`@type {boolean}` `@default {true}`
JSExpression 是否只支持使用 this 来访问上下文变量,假如需要兼容原来的 'state.xxx',则设置为 false
### 应用级设计器
#### enableWorkspaceMode - 应用级设计模式
`@type {boolean}` `@default {false}`
开启应用级设计模式
#### enableAutoOpenFirstWindow
`@type {boolean}` `@default {true}`
应用级设计模式下,自动打开第一个窗口
#### workspaceEmptyComponent
应用级设计模式下,当窗口为空时,展示的占位组件
### 定制组件
#### faultComponent
组件渲染错误时的占位组件
#### notFoundComponent
组件不存在时的占位组件
#### loadingComponent - loading 组件
自定义 loading 组件
### 插件
#### defaultSettingPanelProps
内置设置面板插件的 panelProps
#### defaultOutlinePaneProps
内置大纲树面板插件的 panelProps
### 其他
#### enableStrictPluginMode
`@type {boolean}`
开启严格插件模式,默认值:STRICT_PLUGIN_MODE_DEFAULT , 严格模式下,插件将无法通过 engineOptions 传递自定义配置项
#### requestHandlersMap
数据源引擎的请求处理器映射
#### customPluginTransducer
插件处理中间件,方便提供插件调试能力
类型定义
```typescript
customPluginTransducer: async (originPlugin: IPublicTypePlugin, ctx: IPublicModelPluginContext, options): IPublicTypePlugin;
```
#### defaultOutlinePaneProps
`@type {object}`
大纲树插件面板默认 props
================================================
FILE: docs/docs/api/event.md
================================================
---
title: event - 事件 API
sidebar_position: 10
---
> **@types** [IPublicApiEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/event.ts)
> **@since** v1.0.0
## 模块简介
负责事件处理 API,支持自定义监听事件、触发事件。
## 方法
### on
监听事件
```typescript
/**
* 监听事件
* add monitor to a event
* @param event 事件名称
* @param listener 事件回调
*/
on(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### prependListener
监听事件,会在其他回调函数之前执行
```typescript
/**
* 监听事件,会在其他回调函数之前执行
* @param event 事件名称
* @param listener 事件回调
*/
prependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### off
取消监听事件
```typescript
/**
* 取消监听事件
* cancel a monitor from a event
* @param event 事件名称
* @param listener 事件回调
*/
off(event: string, listener: (...args: any[]) => void): void;
```
### emit
触发事件
```typescript
/**
* 触发事件
* emit a message for a event
* @param event 事件名称
* @param args 事件参数
* @returns
*/
emit(event: string, ...args: any[]): void;
```
## 使用示例
### 事件触发和监听
```typescript
const eventName = 'eventName';
// 事件监听
// 插件中发出的事件,默认以 `common` 为前缀,监听时需要注意下
event.on(`common:${eventName}`);
// 触发事件
event.emit(eventName);
```
### setter 和 setter/plugin 之间的联动
在 A setter 中进行事件注册:
```typescript
import { event } from '@alilc/lowcode-engine';
const SETTER_NAME = 'SetterA';
class SetterA extends React.Component {
componentDidMount() {
// 这里由于面板上会有多个 setter,使用 field.id 来标记 setter 名
this.emitEventName = `${SETTER_NAME}-${this.props.field.id}`;
event.on(`common:${this.emitEventName}.bindEvent`, this.bindEvent)
}
bindEvent = (eventName) => {
// do someting
}
componentWillUnmount() {
// setter 是以实例为单位的,每个 setter 注销的时候需要把事件也注销掉,避免事件池过多
event.off(`common:${this.emitEventName}.bindEvent`, this.bindEvent)
}
}
```
在 B setter 中触发事件,来完成通信:
```typescript
import { event } from '@alilc/lowcode-engine';
class SetterB extends React.Component {
bindFunction = () => {
const { field, value } = this.props;
// 这里展示的和插件进行通信,事件规则是插件名 + 方法
event.emit('eventBindDialog.openDialog', field.name, this.emitEventName);
}
}
```
================================================
FILE: docs/docs/api/hotkey.md
================================================
---
title: hotkey - 快捷键 API
sidebar_position: 10
---
> **@types** [IPublicApiHotkey](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/hotkey.ts)
> **@since** v1.0.0
## 模块简介
绑定快捷键 API,可以自定义项目快捷键使用。
## 方法
### bind
绑定快捷键
```typescript
/**
* 绑定快捷键
* bind hotkey/hotkeys,
* @param combos 快捷键,格式如:['command + s'] 、['ctrl + shift + s'] 等
* @param callback 回调函数
* @param action
* @returns
*/
bind(
combos: string[] | string,
callback: IPublicTypeHotkeyCallback,
action?: string,
): IPublicTypeDisposable;
```
相关 types
- [IPublicTypeHotkeyCallback](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/hotkey-callback.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
## 使用示例
### 基础示例
```typescript
hotkey.bind('command+s', (e) => {
e.preventDefault();
// command+s 快捷键按下时需要执行的逻辑
});
```
### 同时绑定多个快捷键
```typescript
hotkey.bind(['command+s', 'command+c'], (e) => {
e.preventDefault();
// command+s 或者 command+c 快捷键按下时需要执行的逻辑
});
```
### 保存快捷键配置
```typescript
import {
hotkey,
} from '@alilc/lowcode-engine';
function saveSchema(schema) {
// 保存 schema 相关操作
}
const saveSampleHotKey = (ctx: IPublicModelPluginContext) => {
return {
name: 'saveSample',
async init() {
hotkey.bind('command+s', (e) => {
e.preventDefault();
saveSchema();
});
},
};
}
saveSampleHotKey.pluginName = 'saveSampleHotKey';
plugins.register(saveSampleHotKey);
```
================================================
FILE: docs/docs/api/index.md
================================================
---
title: API 总览
sidebar_position: 0
---
引擎提供的公开 API 分为`命名空间`和`模型`两类,其中`命名空间`用于聚合一大类的 API,`模型`为各 API 涉及到的对象模型。
## 命名空间
引擎直接提供以下几大类 API
- skeleton 面板 API
- material 物料 API
- project 模型 API
- simulator-host 模拟器 API
- hotkey 快捷键 API
- setters 设置器 API
- event 事件 API
- config 配置 API
- common 通用 API
- logger 日志 API
- init 初始化 API
## 模型
以下模型通过前面的 API 以返回值等形式间接透出。
- document-model 文档
- node 节点
- node-children 节点孩子
- props 属性集
- prop 属性
- setting-field 设置属性
- setting-top-entry 设置属性集
- component-meta 物料元数据
- selection 画布选中
- detecting 画布 hover
- history 操作历史
- window 低代码设计器窗口模型
- detecting 画布节点悬停模型
- modal-nodes-manager 模态节点管理器模型
- plugin-instance 插件实例
- drop-location 拖拽放置位置模型
## API 设计约定
一些 API 设计约定:
1. 所有 API 命名空间都按照 variables / functions / events 来组织
2. 事件(events)的命名格式为:on[Will|Did]VerbNoun?,参考 [https://code.visualstudio.com/api/references/vscode-api#events](https://code.visualstudio.com/api/references/vscode-api#events)
3. 基于 Disposable 模式,对于事件的绑定、快捷键的绑定函数,返回值则是解绑函数
4. 对于属性的导出,统一用 .xxx 的 getter 模式,(尽量)不使用 .getXxx()
## experimental
说明此模块处于公测阶段, API 可能会发生改变.
================================================
FILE: docs/docs/api/init.md
================================================
---
title: init - 初始化 API
sidebar_position: 0
---
> **@since** v1.0.0
## 模块简介
提供 init 等方法
## 方法
#### init
初始化引擎
**方法定义**
```typescript
function init(container?: Element, options?: IPublicTypeEngineOptions): void
```
[**初始化引擎配置参数列表**](./configOptions)
## 使用示例
```typescript
import { init } from '@alilc/lowcode-engine';
init(document.getElementById('engine'), {
enableCondition: false,
});
```
### 默认打开移动端画布
```typescript
import { init } from '@alilc/lowcode-engine';
init({
device: 'mobile',
});
```
### 使用 utils 第三方工具扩展
```json
import { init } from '@alilc/lowcode-engine';
init({
device: 'mobile',
appHelper: {
utils: {
xxx: () => {console.log('123')},
}
}
});
```
在引擎中即可这样使用。

================================================
FILE: docs/docs/api/logger.md
================================================
---
title: logger - 日志 API
sidebar_position: 10
---
> **@types** [IPublicApiLogger](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/logger.ts)
> **@since** v1.0.0
## 模块简介
引擎日志模块,可以按照 **日志级别 **和** 业务类型 **两个维度来定制日志。
> 注:日志级别可以通过 url query 动态调整,详见下方[查看示例](#查看示例)。
> 参考 [zen-logger](https://web.npm.alibaba-inc.com/package/zen-logger) 实现进行封装
## 方法
日志记录方法
```typescript
/**
* debug info
*/
debug(...args: any | any[]): void;
/**
* normal info output
*/
info(...args: any | any[]): void;
/**
* warning info output
*/
warn(...args: any | any[]): void;
/**
* error info output
*/
error(...args: any | any[]): void;
/**
* log info output
*/
log(...args: any | any[]): void;
```
## 输出示例
```typescript
import { Logger } from '@alilc/lowcode-utils';
const logger = new Logger({ level: 'warn', bizName: 'myPlugin:moduleA' });
logger.log('Awesome Low-Code Engine');
```
## 查看示例
开启查看方式:
- 方式 1:所有 logger 创建时会有默认输出的 level, 默认为 warn , 即只展示 warn , error
- 方式 2:url 上追加 __logConf__进行开启,示例如下
```
https://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn
// 开启所有 bizName的 warn 和 error
https://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=debug
// 开启所有 bizName的 debug, log, info, warn 和 error
https://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=log
// 开启所有 bizName的 log, info, warn 和 error
https://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn|*
// 同 __logConf__=warn
https://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn|bizName
// 开启 bizName 的 debug, log, info, warn 和 error
https://lowcode-engine.cn/demo/demo-general/index.html?__logConf__=warn|partOfBizName
// 开启 bizName like '%partOfBizName%' 的 debug, log, info, warn 和 error
```
================================================
FILE: docs/docs/api/material.md
================================================
---
title: material - 物料 API
sidebar_position: 10
---
> **@types** [IPublicApiMaterial](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/material.ts)
> **@since** v1.0.0
## 模块简介
负责物料相关的 API,包括资产包、设计器辅助层、物料元数据和物料元数据管道函数。
## 变量
### componentsMap
获取组件 map 结构
```typescript
/**
* 获取组件 map 结构
* get map of components
*/
get componentsMap(): { [key: string]: IPublicTypeNpmInfo | ComponentType | object } ;
```
相关类型:[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts)
## 方法
### 资产包
#### setAssets
设置「[资产包](/site/docs/specs/lowcode-spec#2-协议结构)」结构
```typescript
/**
* 设置「资产包」结构
* set data for Assets
* @returns void
*/
setAssets(assets: IPublicTypeAssetsJson): void;
```
相关类型:[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts)
**示例**
直接在项目中引用 npm 包
```javascript
import { material } from '@alilc/lowcode-engine';
import assets from '@alilc/mc-assets-/assets.json';
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 {
// 将下述链接替换为您的物料描述地址即可。
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));
```
#### getAssets
获取「资产包」结构
```typescript
/**
* 获取「资产包」结构
* get AssetsJson data
* @returns IPublicTypeAssetsJson
*/
getAssets(): IPublicTypeAssetsJson;
```
相关类型:[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts)
**示例**
```typescript
import { material } from '@alilc/lowcode-engine';
material.getAssets();
```
#### loadIncrementalAssets
加载增量的「资产包」结构,该增量包会与原有的合并
```typescript
/**
* 加载增量的「资产包」结构,该增量包会与原有的合并
* load Assets incrementally, and will merge this with exiting assets
* @param incrementalAssets
* @returns
*/
loadIncrementalAssets(incrementalAssets: IPublicTypeAssetsJson): Promise;
```
相关类型:[IPublicTypeAssetsJson](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/assets-json.ts)
**示例**
```typescript
import { material } from '@alilc/lowcode-engine';
import assets1 from '@alilc/mc-assets-/assets.json';
import assets2 from '@alilc/mc-assets-/assets.json';
material.setAssets(assets1);
material.loadIncrementalAssets(assets2);
```
更新特定物料的描述文件
```typescript
import { material } from '@alilc/lowcode-engine';
material.loadIncrementalAssets({
version: '',
components: [
{
"componentName": 'Button',
"props": [{ name: 'new', title: 'new', propType: 'string' }]
}
],
})
```
### 设计器辅助层
#### addBuiltinComponentAction
在设计器辅助层增加一个扩展 action
```typescript
/**
* 在设计器辅助层增加一个扩展 action
* add an action button in canvas context menu area
* @param action
*/
addBuiltinComponentAction(action: IPublicTypeComponentAction): void;
```
相关类型:[IPublicTypeComponentAction](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/component-action.ts)
**示例**
新增设计扩展位,并绑定事件
```typescript
import { material } from '@alilc/lowcode-engine';
material.addBuiltinComponentAction({
name: 'myIconName',
content: {
icon: () => 'x',
title: 'hover title',
action(node) {
console.log('myIconName 扩展位被点击');
}
},
important: true,
condition: true,
});
```

#### removeBuiltinComponentAction
移除设计器辅助层的指定 action
```typescript
/**
* 移除设计器辅助层的指定 action
* remove a builtin action button from canvas context menu area
* @param name
*/
removeBuiltinComponentAction(name: string): void;
```
##### 内置设计器辅助 name
- remove:删除
- hide:隐藏
- copy:复制
- lock:锁定,不可编辑
- unlock:解锁,可编辑
**示例**
```typescript
import { material } from '@alilc/lowcode-engine';
material.removeBuiltinComponentAction('myIconName');
```
#### modifyBuiltinComponentAction
修改已有的设计器辅助层的指定 action
```typescript
/**
* 修改已有的设计器辅助层的指定 action
* modify a builtin action button in canvas context menu area
* @param actionName
* @param handle
*/
modifyBuiltinComponentAction(
actionName: string,
handle: (action: IPublicTypeComponentAction) => void,
): void;
```
相关类型:[IPublicTypeComponentAction](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/component-action.ts)
##### 内置设计器辅助 name
- remove:删除
- hide:隐藏
- copy:复制
- lock:锁定,不可编辑
- unlock:解锁,可编辑
**示例**
给原始的 remove 扩展时间添加执行前后的日志
```typescript
import { material } from '@alilc/lowcode-engine';
material.modifyBuiltinComponentAction('remove', (action) => {
const originAction = action.content.action;
action.content.action = (node) => {
console.log('before reomve!');
originAction(node);
console.log('after remove!');
}
});
```
### 右键菜单项
#### addContextMenuOption
添加右键菜单项
```typescript
/**
* 添加右键菜单项
* @param action
*/
addContextMenuOption(action: IPublicTypeContextMenuAction): void;
```
示例
```typescript
import { IPublicEnumContextMenuType } from '@alilc/lowcode-types';
material.addContextMenuOption({
name: 'parentItem',
title: 'Parent Item',
condition: (nodes) => true,
items: [
{
name: 'childItem1',
title: 'Child Item 1',
action: (nodes) => console.log('Child Item 1 clicked', nodes),
condition: (nodes) => true
},
// 分割线
{
type: IPublicEnumContextMenuType.SEPARATOR
name: 'separator.1'
}
// 更多子菜单项...
]
});
```
#### removeContextMenuOption
删除特定右键菜单项
```typescript
/**
* 删除特定右键菜单项
* @param name
*/
removeContextMenuOption(name: string): void;
```
#### adjustContextMenuLayout
调整右键菜单项布局,每次调用都会覆盖之前注册的调整函数,只有最后注册的函数会被应用。
```typescript
/**
* 调整右键菜单项布局
* @param actions
*/
adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void;
```
**示例**
通过 adjustContextMenuLayout 补充分割线
```typescript
material.adjustContextMenuLayout((actions: IPublicTypeContextMenuAction) => {
const names = ['a', 'b'];
const newActions = [];
actions.forEach(d => {
newActions.push(d);
if (names.include(d.name)) {
newActions.push({ type: 'separator' })
}
});
return newActions
})
```
### 物料元数据
#### getComponentMeta
获取指定名称的物料元数据
```typescript
/**
* 获取指定名称的物料元数据
* get component meta by component name
* @param componentName
* @returns
*/
getComponentMeta(componentName: string): IPublicModelComponentMeta | null;
```
相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
**示例**
```typescript
import { material } from '@alilc/lowcode-engine';
material.getComponentMeta('Input');
```
#### getComponentMetasMap
获取所有已注册的物料元数据
```typescript
/**
* 获取所有已注册的物料元数据
* get map of all component metas
* @returns
*/
getComponentMetasMap(): Map;
```
相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
**示例**
```typescript
import { material } from '@alilc/lowcode-engine';
material.getComponentMetasMap();
```
#### refreshComponentMetasMap
刷新 componentMetasMap,可触发模拟器里的 components 重新构建
**@since v1.1.7**
```typescript
refreshComponentMetasMap(): void;
```
### 物料元数据管道函数
#### registerMetadataTransducer
注册物料元数据管道函数,在物料信息初始化时执行。
```typescript
/**
* 注册物料元数据管道函数,在物料信息初始化时执行。
* register transducer to process component meta, which will be
* excuted during component meta`s initialization
* @param transducer
* @param level
* @param id
*/
registerMetadataTransducer(
transducer: IPublicTypeMetadataTransducer,
level?: number,
id?: string | undefined
): void;
```
**示例**
给每一个组件的配置添加高级配置面板,其中有一个是否渲染配置项
```typescript
import { material } from '@alilc/lowcode-engine'
function addonCombine(metadata: TransformedComponentMetadata) {
const { componentName, configure = {} } = metadata;
const advanceGroup = [];
const combined: FieldConfig[] = [];
advanceGroup.push({
name: getConvertedExtraKey('condition'),
title: { type: 'i18n', 'zh-CN': '是否渲染', 'en-US': 'Condition' },
defaultValue: true,
setter: [
{
componentName: 'BoolSetter',
},
{
componentName: 'VariableSetter',
},
],
extraProps: {
display: 'block',
},
});
combined.push({
name: '#advanced',
title: { type: 'i18n', 'zh-CN': '高级', 'en-US': 'Advanced' },
items: advanceGroup,
});
return {
...metadata,
configure: {
...configure,
combined,
},
};
}
material.registerMetadataTransducer(addonCombine, 1, 'parse-func');
```
删除高级 Tab
```typescript
import { material } from '@alilc/lowcode-engine';
import { IPublicTypeFieldConfig } from '@alilc/lowcode-types';
material.registerMetadataTransducer((transducer) => {
const combined: IPublicTypeFieldConfig[] = [];
transducer.configure.combined?.forEach(d => {
if (d.name !== '#advanced') {
combined.push(d);
}
});
return {
...transducer,
configure: {
...transducer.configure,
combined,
}
};
}, 111, 'parse-func');
```
#### getRegisteredMetadataTransducers
获取所有物料元数据管道函数
```typescript
/**
* 获取所有物料元数据管道函数
* get all registered metadata transducers
* @returns {IPublicTypeMetadataTransducer[]}
*/
getRegisteredMetadataTransducers(): IPublicTypeMetadataTransducer[];
```
**示例**
```typescript
import { material } from '@alilc/lowcode-engine'
material.getRegisteredMetadataTransducers();
```
## 事件
### onChangeAssets
监听 assets 变化的事件
```typescript
/**
* 监听 assets 变化的事件
* add callback for assets changed event
* @param fn
*/
onChangeAssets(fn: () => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
**示例**
```typescript
import { material } from '@alilc/lowcode-engine';
material.onChangeAssets(() => {
console.log('asset changed');
});
```
================================================
FILE: docs/docs/api/model/_category_.json
================================================
{
"label": "模型定义 Models",
"position": 100,
"collapsed": false,
"collapsible": true
}
================================================
FILE: docs/docs/api/model/clipboard.md
================================================
---
title: Clipboard
sidebar_position: 14
---
> **@types** [IPublicModelClipboard](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/clipboard.ts)
> **@since** v1.1.0
## 方法
### setData
给剪贴板赋值
```typescript
/**
* 给剪贴板赋值
* set data to clipboard
*
* @param {*} data
* @since v1.1.0
*/
setData(data: any): void;
```
### waitPasteData
设置剪贴板数据设置的回调
```typescript
/**
* 设置剪贴板数据设置的回调
* set callback for clipboard provide paste data
*
* @param {KeyboardEvent} keyboardEvent
* @param {(data: any, clipboardEvent: ClipboardEvent) => void} cb
* @since v1.1.0
*/
waitPasteData(
keyboardEvent: KeyboardEvent,
cb: (data: any, clipboardEvent: ClipboardEvent) => void,
): void;
```
================================================
FILE: docs/docs/api/model/component-meta.md
================================================
---
title: ComponentMeta
sidebar_position: 15
---
> **@types** [IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
> **@since** v1.0.0
## 基本介绍
组件元数据信息模型
## 属性
### componentName
组件名
`@type {string}`
### isContainer
是否是「容器型」组件
`@type {boolean}`
### isMinimalRenderUnit
是否是最小渲染单元
当组件需要重新渲染时:
- 若为最小渲染单元,则只渲染当前组件,
- 若不为最小渲染单元,则寻找到上层最近的最小渲染单元进行重新渲染,直至根节点。
`@type {boolean}`
### isModal
是否为「模态框」组件
`@type {boolean}`
### configure
获取用于设置面板显示用的配置
`@type {IPublicTypeFieldConfig[]}`
相关类型:[IPublicTypeFieldConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/field-config.ts)
### title
标题
`@type {string | IPublicTypeI18nData | ReactElement}`
相关类型:[IPublicTypeI18nData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/i18n-data.ts)
### icon
图标
`@type {IPublicTypeIconType}`
相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/icon-type.ts)
### npm
组件 npm 信息
`@type {IPublicTypeNpmInfo}`
相关类型:[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts)
### availableActions
获取元数据
`@type {IPublicTypeTransformedComponentMetadata}`
相关类型:[IPublicTypeTransformedComponentMetadata](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/transformed-component-metadata.ts)
### advanced
组件元数据中高级配置部分
`@type {IPublicTypeAdvanced}`
相关类型:[IPublicTypeAdvanced](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/advanced.ts)
## 方法
### setNpm
设置 npm 信息
```typescript
/**
* 设置 npm 信息
* set method for npm inforamtion
* @param npm
*/
setNpm(npm: IPublicTypeNpmInfo): void;
```
相关类型:[IPublicTypeNpmInfo](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/npm-info.ts)
### getMetadata
获取元数据
```typescript
/**
* 获取元数据
* get component metadata
*/
getMetadata(): IPublicTypeTransformedComponentMetadata;
```
相关类型:[IPublicTypeTransformedComponentMetadata](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/transformed-component-metadata.ts)
### checkNestingUp
检测当前对应节点是否可被放置在父节点中
```typescript
/**
* 检测当前对应节点是否可被放置在父节点中
* check if the current node could be placed in parent node
* @param my 当前节点
* @param parent 父节点
*/
checkNestingUp(my: IPublicModelNode | IPublicTypeNodeData, parent: any): boolean;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)
### checkNestingDown
检测目标节点是否可被放置在父节点中
```typescript
/**
* 检测目标节点是否可被放置在父节点中
* check if the target node(s) could be placed in current node
* @param my 当前节点
* @param parent 父节点
*/
checkNestingDown(
my: IPublicModelNode | IPublicTypeNodeData,
target: IPublicTypeNodeSchema | IPublicModelNode | IPublicTypeNodeSchema[],
): boolean;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)
- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
### refreshMetadata
刷新元数据,会触发元数据的重新解析和刷新
```typescript
/**
* 刷新元数据,会触发元数据的重新解析和刷新
* refresh metadata
*/
refreshMetadata(): void;
```
================================================
FILE: docs/docs/api/model/detecting.md
================================================
---
title: Detecting
sidebar_position: 6
---
> **@types** [IPublicModelDetecting](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/detecting.ts)
> **@since** v1.0.0
## 基本介绍
画布节点悬停模型
## 属性
### current
当前 hover 的节点
`@type {IPublicModelNode | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
**@since v1.0.16**
### enable
是否启用
`@type {boolean}`
## 方法
### capture
hover 指定节点
```typescript
/**
* hover 指定节点
* capture node with nodeId
* @param id 节点 id
*/
capture(id: string): void;
```
### release
hover 离开指定节点
```typescript
/**
* hover 离开指定节点
* release node with nodeId
* @param id 节点 id
*/
release(id: string): void;
```
### leave
清空 hover 态
```typescript
/**
* 清空 hover 态
* clear all hover state
*/
leave(): void;
```
## 事件
### onDetectingChange
hover 节点变化事件
```typescript
/**
* hover 节点变化事件
* set callback which will be called when hovering object changed.
* @since v1.1.0
*/
onDetectingChange(fn: (node: IPublicModelNode | null) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
**@since v1.1.0**
================================================
FILE: docs/docs/api/model/document-model.md
================================================
---
title: DocumentModel
sidebar_position: 0
---
> **@types** [IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)
> **@since** v1.0.0
## 基本介绍
文档模型
## 属性
### id
唯一 ID
`@type {string}`
### selection
画布节点选中区模型实例
`@type {IPublicModelSelection}`
相关章节:[节点选中区模型](./selection)
相关类型:[IPublicModelSelection](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/selection.ts)
### detecting
画布节点 hover 区模型实例
`@type {IPublicModelDetecting}`
相关章节:[画布节点悬停模型](./detecting)
相关类型:[IPublicModelDetecting](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/detecting.ts)
### history
操作历史模型实例
`@type {IPublicModelHistory}`
相关章节:[操作历史模型](./history)
相关类型:[IPublicModelHistory](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/history.ts)
### project
获取当前文档模型所属的 project
`@type {IPublicApiProject}`
相关类型:[IPublicApiProject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/project.ts)
### root
获取文档的根节点
`@type {IPublicModelNode | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### nodesMap
获取文档下所有节点 Map, key 为 nodeId
`@type {Map} `
相关章节:[节点模型](./node)
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### modalNodesManager
模态节点管理器
`@type {IPublicModelModalNodesManager | null}`
相关章节:[模态节点管理](./modal-nodes-manager)
相关类型:[IPublicModelModalNodesManager](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/modal-nodes-manager.ts)
### dropLocation
文档的 dropLocation
`@type {IPublicModelDropLocation | null}`
相关类型:[IPublicModelDropLocation](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/drop-location.ts)
**@since v1.1.0**
## 方法
### getNodeById
根据 nodeId 返回 [Node](./node) 实例
```typescript
/**
* 根据 nodeId 返回 Node 实例
* get node by nodeId
* @param nodeId
* @returns
*/
getNodeById(nodeId: string): IPublicModelNode | null;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### importSchema
导入 schema
```typescript
/**
* 导入 schema
* import schema data
* @param schema
*/
importSchema(schema: IPublicTypeRootSchema): void;
```
相关类型:[IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)
### exportSchema
导出 schema
```typescript
/**
* 导出 schema
* export schema
* @param stage
* @returns
*/
exportSchema(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined;
```
相关类型:
- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)
- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)
### insertNode
插入节点
```typescript
/**
* 插入节点
* insert a node
*/
insertNode(
parent: IPublicModelNode,
thing: IPublicModelNode,
at?: number | null | undefined,
copy?: boolean | undefined
): IPublicModelNode | null;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### createNode
创建一个节点
```typescript
/**
* 创建一个节点
* create a node
* @param data
* @returns
*/
createNode(data: any): IPublicModelNode | null;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### removeNode
移除指定节点/节点id
```typescript
/**
* 移除指定节点/节点id
* remove a node by node instance or nodeId
* @param idOrNode
*/
removeNode(idOrNode: string | IPublicModelNode): void;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### checkNesting
检查拖拽放置的目标节点是否可以放置该拖拽对象
```typescript
/**
* 检查拖拽放置的目标节点是否可以放置该拖拽对象
* check if dragOjbect can be put in this dragTarget
* @param dropTarget 拖拽放置的目标节点
* @param dragObject 拖拽的对象
* @returns boolean 是否可以放置
* @since v1.0.16
*/
checkNesting(
dropTarget: IPublicModelNode,
dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject
): boolean;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeDragNodeObject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/drag-node-object.ts)
- [IPublicTypeDragNodeDataObject](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/drag-node-object-data.ts)
**@since v1.0.16**
### isDetectingNode
判断是否当前节点处于被探测状态
```typescript
/**
* 判断是否当前节点处于被探测状态
* check is node being detected
* @param node
* @since v1.1.0
*/
isDetectingNode(node: IPublicModelNode): boolean;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
**@since v1.1.0**
## 事件
### onAddNode
当前 document 新增节点事件
```typescript
/**
* 当前 document 新增节点事件
* set callback for event on node is created for a document
*/
onAddNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onMountNode
当前 document 新增节点事件,此时节点已经挂载到 document 上
```typescript
/**
* 当前 document 新增节点事件,此时节点已经挂载到 document 上
* set callback for event on node is mounted to canvas
*/
onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onRemoveNode
当前 document 删除节点事件
```typescript
/**
* 当前 document 删除节点事件
* set callback for event on node is removed
*/
onRemoveNode(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onChangeDetecting
当前 document 的 hover 变更事件
```typescript
/**
* 当前 document 的 hover 变更事件
*
* set callback for event on detecting changed
*/
onChangeDetecting(fn: (node: IPublicModelNode) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onChangeSelection
当前 document 的选中变更事件
```typescript
/**
* 当前 document 的选中变更事件
* set callback for event on selection changed
*/
onChangeSelection(fn: (ids: string[]) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onChangeNodeVisible
当前 document 的节点显隐状态变更事件
```typescript
/**
* 当前 document 的节点显隐状态变更事件
* set callback for event on visibility changed for certain node
* @param fn
*/
onChangeNodeVisible(fn: (node: IPublicModelNode, visible: boolean) => void): IPublicTypeDisposable;
```
- 相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onChangeNodeChildren
当前 document 的节点 children 变更事件
```typescript
onChangeNodeChildren(fn: (info?: IPublicTypeOnChangeOptions) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onChangeNodeProp
当前 document 节点属性修改事件
```typescript
onChangeNodeProp(fn: (info: IPublicTypePropChangeOptions) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onImportSchema
当前 document 导入新的 schema 事件
```typescript
/**
* import schema event
* @param fn
* @since v1.0.15
*/
onImportSchema(fn: (schema: IPublicTypeRootSchema) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)
**@since v1.0.15**
### onFocusNodeChanged
设置聚焦节点变化的回调
```typescript
/**
* 设置聚焦节点变化的回调
* triggered focused node is set mannually from plugin
* @param fn
* @since v1.1.0
*/
onFocusNodeChanged(
fn: (doc: IPublicModelDocumentModel, focusNode: IPublicModelNode) => void,
): IPublicTypeDisposable;
```
相关类型:
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
**@since v1.1.0**
### onDropLocationChanged
设置 DropLocation 变化的回调
```typescript
/**
* 设置 DropLocation 变化的回调
* triggered when drop location changed
* @param fn
* @since v1.1.0
*/
onDropLocationChanged(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
**@since v1.1.0**
================================================
FILE: docs/docs/api/model/dragon.md
================================================
---
title: Dragon
sidebar_position: 99
---
> **@types** [IPublicModelDragon](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/dragon.ts)
> **@since** v1.0.0
## 基本介绍
拖拽对象
### 对应接口
```typescript
import { IPublicModelDragon } from '@alilc/lowcode-types';
```
### 支持版本
**@since** v1.1.0
## 属性
### dragging
是否正在拖动
```typescript
/**
* is dragging or not
*/
get dragging(): boolean;
```
## 方法
### onDragstart
绑定 dragstart 事件
```typescript
/**
* 绑定 dragstart 事件
* bind a callback function which will be called on dragging start
* @param func
* @returns
*/
onDragstart(func: (e: IPublicModelLocateEvent) => any): () => void;
```
### onDrag
绑定 drag 事件
```typescript
/**
* 绑定 drag 事件
* bind a callback function which will be called on dragging
* @param func
* @returns
*/
onDrag(func: (e: IPublicModelLocateEvent) => any): () => void;
```
### onDragend
绑定 dragend 事件
```typescript
/**
* 绑定 dragend 事件
* bind a callback function which will be called on dragging end
* @param func
* @returns
*/
onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): () => void;
```
### from
设置拖拽监听的区域 shell,以及自定义拖拽转换函数 boost
```typescript
/**
* 设置拖拽监听的区域 shell,以及自定义拖拽转换函数 boost
* set a html element as shell to dragon as monitoring target, and
* set boost function which is used to transform a MouseEvent to type
* IPublicTypeDragNodeDataObject.
* @param shell 拖拽监听的区域
* @param boost 拖拽转换函数
*/
from(shell: Element, boost: (e: MouseEvent) => IPublicTypeDragNodeDataObject | null): any;
```
### boost
发射拖拽对象
```typescript
/**
* 发射拖拽对象
* boost your dragObject for dragging(flying)
*
* @param dragObject 拖拽对象
* @param boostEvent 拖拽初始时事件
*/
boost(dragObject: IPublicTypeDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: IPublicModelNode): void;
```
### addSensor
添加投放感应区
```typescript
/**
* 添加投放感应区
* add sensor area
*/
addSensor(sensor: any): void;
```
### removeSensor
移除投放感应
```typescript
/**
* 移除投放感应
* remove sensor area
*/
removeSensor(sensor: any): void;
```
================================================
FILE: docs/docs/api/model/drop-location.md
================================================
---
title: DropLocation
sidebar_position: 13
---
> **@types** [IPublicModelDropLocation](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/drop-location.ts)
> **@since** v1.1.0
## 基本介绍
拖拽放置位置模型
## 属性
### target
拖拽放置位置目标
`@type {IPublicModelNode | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### detail
拖拽放置位置详情
`@type {IPublicTypeLocationDetail}`
相关类型:[IPublicTypeLocationDetail](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/location-detail.ts)
### event
拖拽放置位置对应的事件
`@type {IPublicTypeLocationDetail}`
相关类型:[IPublicModelLocateEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/location-event.ts)
## 方法
### clone
获取一份当前对象的克隆
```typescript
/**
* 获取一份当前对象的克隆
* get a clone object of current dropLocation
*/
clone(event: IPublicModelLocateEvent): IPublicModelDropLocation;
```
相关类型:[IPublicModelLocateEvent](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/location-event.ts)
================================================
FILE: docs/docs/api/model/editor-view.md
================================================
---
title: EditorView
sidebar_position: 12
---
> **[@experimental](./#experimental)**
> **@types** [IPublicModelEditorView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/editor-view.ts)
> **@since** v1.1.7
窗口编辑视图
## 类型定义
```
import { IPublicModelPluginContext } from "./plugin-context";
export interface IPublicModelEditorView extends IPublicModelPluginContext {};
```
相关类型定义: [IPublicModelPluginContext](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-context.ts)
================================================
FILE: docs/docs/api/model/history.md
================================================
---
title: History
sidebar_position: 5
---
> **@types** [IPublicModelHistory](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/history.ts)
> **@since** v1.0.0
## 基本介绍
操作历史记录模型
## 方法
### go
历史记录跳转到指定位置
```typescript
/**
* 历史记录跳转到指定位置
* go to a specific history
* @param cursor
*/
go(cursor: number): void;
```
### back
历史记录后退
```typescript
/**
* 历史记录后退
* go backward in history
*/
back(): void;
```
### forward
forward()
历史记录前进
```typescript
/**
* 历史记录前进
* go forward in history
*/
forward(): void;
```
### savePoint
保存当前状态
```typescript
/**
* 保存当前状态
* do save current change as a record in history
*/
savePoint(): void;
```
### isSavePoint
当前是否是「保存点」,即是否有状态变更但未保存
```typescript
/**
* 当前是否是「保存点」,即是否有状态变更但未保存
* check if there is unsaved change for history
*/
isSavePoint(): boolean;
```
### getState
获取 state,判断当前是否为「可回退」、「可前进」的状态
```typescript
/**
* 获取 state,判断当前是否为「可回退」、「可前进」的状态
* get flags in number which indicat current change state
*
* | 1 | 1 | 1 |
* | -------- | -------- | -------- |
* | modified | redoable | undoable |
* eg:
* 7 means : modified && redoable && undoable
* 5 means : modified && undoable
*/
getState(): number;
```
## 事件
### onChangeState
监听 state 变更事件
```typescript
/**
* 监听 state 变更事件
* monitor on stateChange event
* @param func
*/
onChangeState(func: () => any): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onChangeCursor
监听历史记录游标位置变更事件
```typescript
/**
* 监听历史记录游标位置变更事件
* monitor on cursorChange event
* @param func
*/
onChangeCursor(func: () => any): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
================================================
FILE: docs/docs/api/model/modal-nodes-manager.md
================================================
---
title: ModalNodesManager
sidebar_position: 7
---
> **@types** [IPublicModelModalNodesManager](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/modal-nodes-manager.ts)
> **@since** v1.0.0
## 基本介绍
模态节点管理器模型
## 方法
### setNodes
设置模态节点,触发内部事件
```typescript
/**
* 设置模态节点,触发内部事件
* set modal nodes, trigger internal events
*/
setNodes(): void;
```
### getModalNodes
获取模态节点(们)
```typescript
/**
* 获取模态节点(们)
* get modal nodes
*/
getModalNodes(): IPublicModelNode[];
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### getVisibleModalNode
获取当前可见的模态节点
```typescript
/**
* 获取当前可见的模态节点
* get current visible modal node
*/
getVisibleModalNode(): IPublicModelNode | null;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### hideModalNodes
隐藏模态节点(们)
```typescript
/**
* 隐藏模态节点(们)
* hide modal nodes
*/
hideModalNodes(): void;
```
### setVisible
设置指定节点为可见态
```typescript
/**
* 设置指定节点为可见态
* set specific model node as visible
* @param node IPublicModelNode
*/
setVisible(node: IPublicModelNode): void;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### setInvisible
设置指定节点为不可见态
```typescript
/**
* 设置指定节点为不可见态
* set specific model node as invisible
* @param node IPublicModelNode
*/
setInvisible(node: IPublicModelNode): void;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
================================================
FILE: docs/docs/api/model/node-children.md
================================================
---
title: NodeChildren
sidebar_position: 2
---
> **@types** [IPublicModelNodeChildren](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node-children.ts)
> **@since** v1.0.0
## 基本介绍
节点孩子模型
## 属性
### owner
返回当前 children 实例所属的节点实例
`@type {IPublicModelNode | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### size
children 内的节点实例数
`@type {number}`
### isEmptyNode
是否为空
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isEmpty`
### notEmptyNode
是否不为空
`@type {boolean}`
**@since v1.1.0**
## 方法
### delete
删除指定节点
```typescript
/**
* 删除指定节点
* delete the node
* @param node
*/
delete(node: IPublicModelNode): boolean;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### insert
插入一个节点
```typescript
/**
* 插入一个节点
* insert the node
* @param node
*/
insert(node: IPublicModelNode): boolean;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### indexOf
返回指定节点的下标
```typescript
/**
* 返回指定节点的下标
* get index of node in current children
* @param node
* @returns
*/
indexOf(node: IPublicModelNode): number;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### splice
类似数组 splice 操作
```typescript
/**
* 类似数组 splice 操作
* provide the same function with {Array.prototype.splice}
* @param start
* @param deleteCount
* @param node
*/
splice(start: number, deleteCount: number, node?: IPublicModelNode): any;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### get
返回指定下标的节点
```typescript
/**
* 返回指定下标的节点
* get node with index
* @param index
* @returns
*/
get(index: number): IPublicModelNode | null;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### has
是否包含指定节点
```typescript
/**
* 是否包含指定节点
* check if node exists in current children
* @param node
* @returns
*/
has(node: IPublicModelNode): boolean;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### forEach
类似数组的 forEach
```typescript
/**
* 类似数组的 forEach
* provide the same function with {Array.prototype.forEach}
* @param fn
*/
forEach(fn: (node: IPublicModelNode, index: number) => void): void;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### reverse
类似数组的 reverse
```typescript
/**
* 类似数组的 reverse
* provide the same function with {Array.prototype.reverse}
*/
reverse(): IPublicModelNode[];
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### map
类似数组的 map
```typescript
/**
* 类似数组的 map
* provide the same function with {Array.prototype.map}
* @param fn
*/
map(fn: (node: IPublicModelNode, index: number) => T[]): any[] | null;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### every
类似数组的 every
```typescript
/**
* 类似数组的 every
* provide the same function with {Array.prototype.every}
* @param fn
*/
every(fn: (node: IPublicModelNode, index: number) => boolean): boolean;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### some
类似数组的 some
```typescript
/**
* 类似数组的 some
* provide the same function with {Array.prototype.some}
* @param fn
*/
some(fn: (node: IPublicModelNode, index: number) => boolean): boolean;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### filter
类似数组的 filter
```typescript
/**
* 类似数组的 filter
* provide the same function with {Array.prototype.filter}
* @param fn
*/
filter(fn: (node: IPublicModelNode, index: number) => boolean): any;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### find
类似数组的 find
```typescript
/**
* 类似数组的 find
* provide the same function with {Array.prototype.find}
* @param fn
*/
find(fn: (node: IPublicModelNode, index: number) => boolean): IPublicModelNode | null;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### reduce
类似数组的 reduce
```typescript
/**
* 类似数组的 reduce
* provide the same function with {Array.prototype.reduce}
* @param fn
*/
reduce(fn: (acc: any, cur: IPublicModelNode) => any, initialValue: any): void;
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### importSchema
导入 schema
```typescript
/**
* 导入 schema
* import schema
* @param data
*/
importSchema(data?: IPublicTypeNodeData | IPublicTypeNodeData[]): void;
```
相关类型:[IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)
### exportSchema
导出 schema
```typescript
/**
* 导出 schema
* export schema
* @param stage
*/
exportSchema(stage: IPublicEnumTransformStage): IPublicTypeNodeSchema;
```
相关类型:
- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)
- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
### mergeChildren
执行新增、删除、排序等操作
```typescript
/**
* 执行新增、删除、排序等操作
* excute remove/add/sort operations
* @param remover
* @param adder
* @param sorter
*/
mergeChildren(
remover: (node: IPublicModelNode, idx: number) => boolean,
adder: (children: IPublicModelNode[]) => IPublicTypeNodeData[] | null,
sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number
): any;
```
相关类型:
- [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
- [IPublicTypeNodeData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-data.ts)
================================================
FILE: docs/docs/api/model/node.md
================================================
---
title: Node
sidebar_position: 1
---
> **@types** [IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
> **@since** v1.0.0
## 基本介绍
节点模型
## 属性
### id
节点 id
`@type {string}`
### title
节点标题
`@type {string | IPublicTypeI18nData | ReactElement}`
相关类型:[IPublicTypeI18nData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/i18n-data.ts)
### isContainerNode
是否为「容器型」节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isContainer`
### isRootNode
是否为根节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isRoot`
### isEmptyNode
是否为空节点(无 children 或者 children 为空)
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isEmpty`
### isPageNode
是否为 Page 节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isPage`
### isComponentNode
是否为 Component 节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isComponent`
### isModalNode
是否为「模态框」节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isModal`
### isSlotNode
是否为插槽节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isSlot`
### isParentalNode
是否为父类/分支节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isParental`
### isLeafNode
是否为叶子节点
`@type {boolean}`
**@since v1.1.0**
> v1.1.0 之前请使用 `isLeaf`
### isLocked
获取当前节点的锁定状态
**@since v1.0.16**
### isRGLContainerNode
设置为磁贴布局节点,使用方式可参考:[磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw)
`@type {boolean}`
**@since v1.1.0**
> v1.0.16 - v1.1.0 请使用 `isRGLContainer`
### index
下标
`@type {number}`
### icon
图标
`@type {IPublicTypeIconType}`
相关类型:[IPublicTypeIconType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/icon-type.ts)
### zLevel
节点所在树的层级深度,根节点深度为 0
`@type {number}`
### componentName
节点 componentName
`@type {string}`
### componentMeta
节点的物料元数据
`@type {IPublicModelComponentMeta | null}`
相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
### document
获取节点所属的[文档模型](./document-model)对象
`@type {IPublicModelDocumentModel | null}`
相关类型:[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)
### prevSibling
获取当前节点的前一个兄弟节点
`@type {IPublicModelNode | null}`
### nextSibling
获取当前节点的后一个兄弟节点
`@type {IPublicModelNode | null}`
### parent
获取当前节点的父亲节点
`@type {IPublicModelNode | null}`
### children
获取当前节点的孩子节点模型
`@type {IPublicModelNodeChildren | null}`
相关类型:[IPublicModelNodeChildren](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node-children.ts)
### slots
节点上挂载的插槽节点们
`@type {IPublicModelNode[]}`
### slotFor
当前节点为插槽节点时,返回节点对应的属性实例
`@type {IPublicModelProp | null}`
相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)
### props
返回节点的属性集
`@type {IPublicModelProps | null}`
相关类型:[IPublicModelProps](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/props.ts)
### propsData
返回节点的属性集值
`@type {IPublicTypePropsMap | IPublicTypePropsList | null}`
相关类型:
- [IPublicTypePropsMap](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-map.ts)
- [IPublicTypePropsList](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-list.ts)
### conditionGroup
获取条件组
`@type {IPublicModelExclusiveGroup | null}`
相关类型:[IPublicModelExclusiveGroup](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/exclusive-group.ts)
**@since v1.1.0**
### schema
获取符合搭建协议 - 节点 schema 结构
`@type {IPublicTypeNodeSchema | null}`
相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
### settingEntry
获取对应的 setting entry
`@type {IPublicModelSettingTopEntry}`
相关章节:[设置器顶层操作对象](./setting-top-entry)
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
### visible
当前节点是否可见
`@type {boolean}`
**@since v1.1.0**
## 方法
### getRect
返回节点的尺寸、位置信息
```typescript
/**
* 返回节点的尺寸、位置信息
* get rect information for this node
*/
getRect(): DOMRect | null;
```
### hasSlots
是否有挂载插槽节点
```typescript
/**
* 是否有挂载插槽节点
* check if current node has slots
*/
hasSlots(): boolean;
```
### hasCondition
是否设定了渲染条件
```typescript
/**
* 是否设定了渲染条件
* check if current node has condition value set
*/
hasCondition(): boolean;
```
### hasLoop
是否设定了循环数据
```typescript
/**
* 是否设定了循环数据
* check if loop is set for this node
*/
hasLoop(): boolean;
```
### getProp
获取指定 path 的属性模型实例
```typescript
/**
* 获取指定 path 的属性模型实例
* get prop by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
*/
getProp(path: string, createIfNone: boolean): IPublicModelProp | null;
```
相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)
### getPropValue
获取指定 path 的属性模型实例值
```typescript
/**
* 获取指定 path 的属性模型实例值
* get prop value by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
*/
getPropValue(path: string): any;
```
### getExtraProp
获取指定 path 的属性模型实例,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
```typescript
/**
* 获取指定 path 的属性模型实例,
* 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
*
* get extra prop by path, an extra prop means a prop not exists in the `props`
* but as siblint of the `props`
* @param path 属性路径,支持 a / a.b / a.0 等格式
* @param createIfNone 当没有属性的时候,是否创建一个属性
*/
getExtraProp(path: string, createIfNone?: boolean): IPublicModelProp | null;
```
相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)
### getExtraPropValue
获取指定 path 的属性模型实例,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
```typescript
/**
* 获取指定 path 的属性模型实例,
* 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
*
* get extra prop value by path, an extra prop means a prop not exists in the `props`
* but as siblint of the `props`
* @param path 属性路径,支持 a / a.b / a.0 等格式
* @returns
*/
getExtraPropValue(path: string): any;
```
### setPropValue
setPropValue(path: string, value: CompositeValue)
设置指定 path 的属性模型实例值
```typescript
/**
* 设置指定 path 的属性模型实例值
* set value for prop with path
* @param path 属性路径,支持 a / a.b / a.0 等格式
* @param value 值
*/
setPropValue(path: string, value: IPublicTypeCompositeValue): void;
```
相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
### setExtraPropValue
设置指定 path 的属性模型实例值
```typescript
/**
* 设置指定 path 的属性模型实例值
* set value for extra prop with path
* @param path 属性路径,支持 a / a.b / a.0 等格式
* @param value 值
*/
setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void;
```
相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
### importSchema
导入节点数据
```typescript
/**
* 导入节点数据
* import node schema
* @param data
*/
importSchema(data: IPublicTypeNodeSchema): void;
```
相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
### exportSchema
导出节点数据
```typescript
/**
* 导出节点数据
* export schema from this node
* @param stage
* @param options
*/
exportSchema(stage: IPublicEnumTransformStage, options?: any): IPublicTypeNodeSchema;
```
相关类型:
- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)
- [IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
### insertBefore
在指定位置之前插入一个节点
```typescript
/**
* 在指定位置之前插入一个节点
* insert a node befor current node
* @param node
* @param ref
* @param useMutator
*/
insertBefore(
node: IPublicModelNode,
ref?: IPublicModelNode | undefined,
useMutator?: boolean,
): void;
```
### insertAfter
在指定位置之后插入一个节点
```typescript
/**
* 在指定位置之后插入一个节点
* insert a node after this node
* @param node
* @param ref
* @param useMutator
*/
insertAfter(
node: IPublicModelNode,
ref?: IPublicModelNode | undefined,
useMutator?: boolean,
): void;
```
### replaceChild
替换指定子节点
```typescript
/**
* 替换指定子节点
* replace a child node with data provided
* @param node 待替换的子节点
* @param data 用作替换的节点对象或者节点描述
* @returns
*/
replaceChild(node: IPublicModelNode, data: any): IPublicModelNode | null;
```
### replaceWith
将当前节点替换成指定节点描述
```typescript
/**
* 将当前节点替换成指定节点描述
* replace current node with a new node schema
* @param schema
*/
replaceWith(schema: IPublicTypeNodeSchema): any;
```
相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
### select
选中当前节点实例
```typescript
/**
* 选中当前节点实例
* select current node
*/
select(): void;
```
### hover
设置悬停态
```typescript
/**
* 设置悬停态
* set hover value for current node
* @param flag
*/
hover(flag: boolean): void;
```
### lock
设置节点锁定状态
```typescript
/**
* 设置节点锁定状态
* set lock value for current node
* @param flag
* @since v1.0.16
*/
lock(flag?: boolean): void;
```
**@since v1.0.16**
### remove
删除当前节点实例
```typescript
/**
* 删除当前节点实例
* remove current node
*/
remove(): void;
```
### mergeChildren
执行新增、删除、排序等操作
```typescript
/**
* 执行新增、删除、排序等操作
* excute remove/add/sort operations on node`s children
*
* @since v1.1.0
*/
mergeChildren(
remover: (node: IPublicModelNode, idx: number) => boolean,
adder: (children: IPublicModelNode[]) => any,
sorter: (firstNode: IPublicModelNode, secondNode: IPublicModelNode) => number
): any;
```
**@since v1.1.0**
### contains
当前节点是否包含某子节点
```typescript
/**
* 当前节点是否包含某子节点
* check if current node contains another node as a child
* @param node
* @since v1.1.0
*/
contains(node: IPublicModelNode): boolean;
```
**@since v1.1.0**
### canPerformAction
是否可执行某 action
```typescript
/**
* 是否可执行某 action
* check if current node can perform certain aciton with actionName
* @param actionName action 名字
* @since v1.1.0
*/
canPerformAction(actionName: string): boolean;
```
**@since v1.1.0**
### isConditionalVisible
获取该节点的 ConditionalVisible 值
```typescript
/**
* 获取该节点的 ConditionalVisible 值
* check if current node ConditionalVisible
* @since v1.1.0
*/
isConditionalVisible(): boolean | undefined;
```
**@since v1.1.0**
### setConditionalVisible
设置该节点的 ConditionalVisible 为 true
```typescript
/**
* 设置该节点的 ConditionalVisible 为 true
* make this node as conditionalVisible === true
* @since v1.1.0
*/
setConditionalVisible(): void;
```
**@since v1.1.0**
### getDOMNode
获取节点实例对应的 dom 节点
```typescript
/**
* 获取节点实例对应的 dom 节点
*/
getDOMNode(): HTMLElement;
```
### getRGL
获取磁贴相关信息
```typescript
/**
* 获取磁贴相关信息
*/
getRGL(): {
isContainerNode: boolean;
isEmptyNode: boolean;
isRGLContainerNode: boolean;
isRGLNode: boolean;
isRGL: boolean;
rglNode: IPublicModelNode | null;
}
```
================================================
FILE: docs/docs/api/model/plugin-instance.md
================================================
---
title: PluginInstance
sidebar_position: 12
---
> **@types** [IPublicModelPluginInstance](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-instance.ts)
> **@since** v1.1.0
## 基本介绍
插件实例
## 属性
### pluginName
插件名字
`@type {string}`
### dep
插件依赖
`@type {string[]}`
### disabled
插件是否禁用
`@type {boolean}`
### meta
插件 meta 信息
`@type {IPublicTypePluginMeta}`
相关类型:[IPublicTypePluginMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-meta.ts)
================================================
FILE: docs/docs/api/model/prop.md
================================================
---
title: Prop
sidebar_position: 3
---
> **@types** [IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)
> **@since** v1.0.0
## 基本介绍
属性模型
## 属性
### id
id
`@type {string}`
### key
key 值
`@type {string | number | undefined}`
### path
返回当前 prop 的路径
`@type {string[]}`
### node
返回所属的节点实例
`@type {IPublicModelNode | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### slotNode
当本 prop 代表一个 Slot 时,返回对应的 slotNode
`@type {IPublicModelNode | undefined | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
## 方法
### setValue
设置值
```typescript
/**
* 设置值
* set value for this prop
* @param val
*/
setValue(val: IPublicTypeCompositeValue): void;
```
相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
### getValue
获取值
```typescript
/**
* 获取值
* get value of this prop
*/
getValue(): any;
```
### remove
移除值
```typescript
/**
* 移除值
* remove value of this prop
* @since v1.0.16
*/
remove(): void;
```
**@since v1.0.16**
### exportSchema
导出值
```typescript
/**
* 导出值
* export schema
* @param stage
*/
exportSchema(stage: IPublicEnumTransformStage): IPublicTypeCompositeValue;
```
相关类型:
- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)
- [IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
================================================
FILE: docs/docs/api/model/props.md
================================================
---
title: Props
sidebar_position: 4
---
> **@types** [IPublicModelProps](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/props.ts)
> **@since** v1.0.0
## 基本介绍
属性集模型
## 属性
### id
id
`@type {string}`
### path
返回当前 props 的路径
`@type {string[]}`
### node
返回当前属性集所属的节点实例
`@type {IPublicModelNode | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
## 方法
### getProp
获取指定 path 的属性模型实例
```typescript
/**
* 获取指定 path 的属性模型实例
* get prop by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
*/
getProp(path: string): IPublicModelProp | null;
```
相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)
### getPropValue
获取指定 path 的属性模型实例值
```typescript
/**
* 获取指定 path 的属性模型实例值
* get value of prop by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
*/
getPropValue(path: string): any;
```
### getExtraProp
获取指定 path 的属性模型实例,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
```typescript
/**
* 获取指定 path 的属性模型实例,
* 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
* get extra prop by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
*/
getExtraProp(path: string): IPublicModelProp | null;
```
相关类型:[IPublicModelProp](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/prop.ts)
### getExtraPropValue
获取指定 path 的属性模型实例值,注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
```typescript
/**
* 获取指定 path 的属性模型实例值
* 注:导出时,不同于普通属性,该属性并不挂载在 props 之下,而是与 props 同级
* get value of extra prop by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
*/
getExtraPropValue(path: string): any;
```
### setPropValue
设置指定 path 的属性模型实例值
```typescript
/**
* 设置指定 path 的属性模型实例值
* set value of prop by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
* @param value 值
*/
setPropValue(path: string, value: IPublicTypeCompositeValue): void;
```
相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
### setExtraPropValue
设置指定 path 的属性模型实例值
```typescript
/**
* 设置指定 path 的属性模型实例值
* set value of extra prop by path
* @param path 属性路径,支持 a / a.b / a.0 等格式
* @param value 值
*/
setExtraPropValue(path: string, value: IPublicTypeCompositeValue): void;
```
相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
### has
当前 props 是否包含某 prop
```typescript
/**
* 当前 props 是否包含某 prop
* check if the specified key is existing or not.
* @param key
* @since v1.1.0
*/
has(key: string): boolean;
```
**@since v1.1.0**
### add
添加一个 prop
```typescript
/**
* 添加一个 prop
* add a key with given value
* @param value
* @param key
* @since v1.1.0
*/
add(value: IPublicTypeCompositeValue, key?: string | number | undefined): any;
```
相关类型:[IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
**@since v1.1.0**
================================================
FILE: docs/docs/api/model/resource.md
================================================
---
title: Resource
sidebar_position: 13
---
> **[@experimental](./#experimental)**
> **@types** [IPublicModelResource](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/resource.ts)
> **@since** v1.1.0
## 属性
### title
资源标题
`@type {string}`
### id
资源 id
`@type {string}`
### name
资源名字
`@type {string}`
### type
资源类型
`@type {string}`
### category
资源分类
`@type {string}`
### icon
资源 icon
`@type {ReactElement}`
### options
资源配置信息
`@type {Object}`
### config
资源配置信息
`@type {Object}`
================================================
FILE: docs/docs/api/model/selection.md
================================================
---
title: Selection
sidebar_position: 6
---
> **@types** [IPublicModelSelection](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/selection.ts)
> **@since** v1.0.0
## 基本介绍
画布节点选中模型
## 属性
### selected
返回选中的节点 id
`@type {string[]}`
### node
返回选中的节点(如多个节点只返回第一个)
`@type {IPublicModelNode | null}`
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
**@since v1.1.0**
## 方法
### select
选中指定节点(覆盖方式)
```typescript
/**
* 选中指定节点(覆盖方式)
* select node with id, this will override current selection
* @param id
*/
select(id: string): void;
```
### selectAll
批量选中指定节点们
```typescript
/**
* 批量选中指定节点们
* select node with ids, this will override current selection
*
* @param ids
*/
selectAll(ids: string[]): void;
```
### remove
**取消选中**选中的指定节点,不会删除组件
```typescript
/**
* 移除选中的指定节点
* remove node from selection with node id
* @param id
*/
remove(id: string): void;
```
### clear
**取消选中**所有选中节点,不会删除组件
```typescript
/**
* 清除所有选中节点
* clear current selection
*/
clear(): void;
```
### has
判断是否选中了指定节点
```typescript
/**
* 判断是否选中了指定节点
* check if node with specific id is selected
* @param id
*/
has(id: string): boolean;
```
### add
选中指定节点(增量方式)
```typescript
/**
* 选中指定节点(增量方式)
* add node with specific id to selection
* @param id
*/
add(id: string): void;
```
### getNodes
获取选中的节点实例
```typescript
/**
* 获取选中的节点实例
* get selected nodes
*/
getNodes(): IPublicModelNode[];
```
相关类型:[IPublicModelNode](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/node.ts)
### getTopNodes
获取选区的顶层节点
例如选中的节点为:
- DivA
- ChildrenA
- DivB
getNodes 返回的是 [DivA、ChildrenA、DivB],getTopNodes 返回的是 [DivA、DivB],其中 ChildrenA 由于是二层节点,getTopNodes 不会返回
```typescript
/**
* 获取选区的顶层节点
* get seleted top nodes
* for example:
* getNodes() returns [A, subA, B], then
* getTopNodes() will return [A, B], subA will be removed
* @since v1.0.16
*/
getTopNodes(includeRoot?: boolean): IPublicModelNode[];
```
**@since v1.0.16**
## 事件
### onSelectionChange
注册 selection 变化事件回调
```typescript
/**
* 注册 selection 变化事件回调
* set callback which will be called when selection is changed
* @since v1.1.0
*/
onSelectionChange(fn: (ids: string[]) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
**@since v1.1.0**
================================================
FILE: docs/docs/api/model/setting-field.md
================================================
---
title: SettingField
sidebar_position: 6
---
> **@types** [IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)
## 基本介绍
setter 设置器操作对象
## 属性
#### isGroup
获取设置属性的 isGroup
`@type {boolean}`
#### id
获取设置属性的 id
`@type {string}`
#### name
获取设置属性的 name
`@type {string | number | undefined}`
#### key
获取设置属性的 key
`@type {string | number | undefined}`
#### path
获取设置属性的 path
`@type {(string | number)[]}`
#### title
获取设置属性的 title
`@type {string}`
#### setter
获取设置属性的 setter
`@type {IPublicTypeSetterType | null}`
#### expanded
获取设置属性的 expanded
`@type {boolean}`
#### extraProps
获取设置属性的 extraProps
`@type {IPublicTypeFieldExtraProps}`
#### props
`@type {IPublicModelSettingTopEntry}`
相关章节:[设置器顶层操作对象](./setting-top-entry)
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
#### node
获取设置属性对应的节点实例
`@type {IPublicModelNode | null}`
#### parent
获取设置属性的父设置属性
`@type {IPublicModelSettingTopEntry | IPublicModelSettingField}`
相关章节:[设置器顶层操作对象](./setting-top-entry)
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
#### top
获取顶级设置属性
`@type {IPublicModelSettingTopEntry}`
相关章节:[设置器顶层操作对象](./setting-top-entry)
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
#### isSettingField
是否是 SettingField 实例
`@type {boolean}`
#### componentMeta
`@type {IPublicModelComponentMeta}`
相关类型:[IPublicModelComponentMeta](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/component-meta.ts)
#### items
获取设置属性的 items
`@type {Array}`
相关类型:[IPublicTypeCustomView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/custom-view.ts)
## 方法
#### setKey
设置 key 值
```
/**
* 设置 key 值
* @param key
*/
setKey(key: string | number): void;
```
#### setValue
设置值
```
/**
* 设置值
* @param val 值
*/
setValue(val: IPublicTypeCompositeValue, extraOptions?: IPublicTypeSetValueOptions): void;
```
相关类型:
- [IPublicTypeCompositeValue](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/composite-value.ts)
- [IPublicTypeSetValueOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/set-value-options.ts)
#### setPropValue
设置子级属性值
```
/**
* 设置子级属性值
* @param propName 子属性名
* @param value 值
*/
setPropValue(propName: string | number, value: any): void;
```
#### clearPropValue
清空指定属性值
```
/**
* 清空指定属性值
* @param propName
*/
clearPropValue(propName: string | number): void;
```
#### getDefaultValue
获取配置的默认值
```
/**
* 获取配置的默认值
* @returns
*/
getDefaultValue(): any;
```
#### getValue
获取值
```
/**
* 获取值
* @returns
*/
getValue(): any;
```
#### getPropValue
获取子级属性值
```
/**
* 获取子级属性值
* @param propName 子属性名
* @returns
*/
getPropValue(propName: string | number): any;
```
#### getExtraPropValue
获取顶层附属属性值
```
/**
* 获取顶层附属属性值
*/
getExtraPropValue(propName: string): any;
```
#### setExtraPropValue
设置顶层附属属性值
```
/**
* 设置顶层附属属性值
*/
setExtraPropValue(propName: string, value: any): void;
```
#### getProps
获取设置属性集
```
/**
* 获取设置属性集
* @returns
*/
getProps(): IPublicModelSettingTopEntry;
```
相关章节:[设置器顶层操作对象](./setting-top-entry)
相关类型:[IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
#### isUseVariable
是否绑定了变量
```
/**
* 是否绑定了变量
* @returns
*/
isUseVariable(): boolean;
```
#### setUseVariable
设置绑定变量
```
/**
* 设置绑定变量
* @param flag
*/
setUseVariable(flag: boolean): void;
```
#### createField
创建一个设置 field 实例
```
/**
* 创建一个设置 field 实例
* @param config
* @returns
*/
createField(config: IPublicTypeFieldConfig): IPublicModelSettingField;
```
相关类型:[IPublicTypeFieldConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/field-config.ts)
#### getMockOrValue
获取值,当为变量时,返回 mock
```
/**
* 获取值,当为变量时,返回 mock
* @returns
*/
getMockOrValue(): any;
```
#### purge
销毁当前 field 实例
```
/**
* 销毁当前 field 实例
*/
purge(): void;
```
#### remove
移除当前 field 实例
```
/**
* 移除当前 field 实例
*/
remove(): void;
```
## 事件
#### onEffect
设置 autorun
```
/**
* 设置 autorun
* @param action
* @returns
*/
onEffect(action: () => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
================================================
FILE: docs/docs/api/model/setting-top-entry.md
================================================
---
title: SettingTopEntry
sidebar_position: 6
---
> **@types** [IPublicModelSettingTopEntry](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-top-entry.ts)
## 基本介绍
setter 设置器顶层操作对象
## 属性
#### node
返回所属的节点实例
`@type {IPublicModelNode | null}`
## 方法
#### get
获取子级属性对象
```
/**
* 获取子级属性对象
* @param propName
* @returns
*/
get(propName: string | number): IPublicModelSettingField | null;
```
相关章节:[设置器操作对象](./setting-field)
相关类型:[IPublicModelSettingField](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/setting-field.ts)
#### getPropValue
获取指定 propName 的值
```
/**
* 获取指定 propName 的值
* @param propName
* @returns
*/
getPropValue(propName: string | number): any;
```
#### setPropValue
设置指定 propName 的值
```
/**
* 设置指定 propName 的值
* @param propName
* @param value
*/
setPropValue(propName: string | number, value: any): void;
```
#### clearPropValue
清除指定 propName 的值
```
/**
* 清除指定 propName 的值
* @param propName
*/
clearPropValue(propName: string | number): void;
```
================================================
FILE: docs/docs/api/model/simulatorRender.md
================================================
---
title: SimulatorRender
sidebar_position: 6
---
> **@types** [IPublicModelSimulatorRender](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/simulator-render.ts)
> **@since** v1.0.0
## 基本介绍
画布节点选中模型
## 属性
### components
画布组件列表
```typescript
/**
* 画布组件列表
*/
components: {
[key: string]: any;
}
```
## 方法
### rerender
触发画布重新渲染
```typescript
/**
* 触发画布重新渲染
*/
rerender: () => void;
```
================================================
FILE: docs/docs/api/model/window.md
================================================
---
title: Window
sidebar_position: 12
---
> **[@experimental](./#experimental)**
> **@types** [IPublicModelWindow](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/window.ts)
> **@since** v1.1.0
## 基本介绍
低代码设计器窗口模型
## 属性
### id
窗口唯一 id
`@type {string}`
### title
窗口标题
`@type {string}`
### icon
`@type {ReactElement}`
### resource
窗口对应资源
`@type {IPublicModelResource}`
关联模型 [IPublicModelResource](./resource)
### currentEditorView
窗口当前视图
`@type {IPublicModelEditorView}`
关联模型 [IPublicModelEditorView](./editor-view)
**@since v1.1.7**
### editorViews
窗口所有视图
`@type {IPublicModelEditorView[]}`
关联模型 [IPublicModelEditorView](./editor-view)
**@since v1.1.7**
## 方法
### importSchema
当前窗口导入 schema, 会调用当前窗口对应资源的 import 钩子
```typescript
function importSchema(schema: IPublicTypeNodeSchema): void
```
相关类型:[IPublicTypeNodeSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/node-schema.ts)
### changeViewType
修改当前窗口视图类型
```typescript
function changeViewType(viewName: string): void
```
### save
当前窗口的保存方法,会调用当前窗口对应资源的 save 钩子
```typescript
function save(): Promise(void)
```
## 事件
### onChangeViewType
窗口视图变更事件
```
onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onSave
窗口视图保存事件
```
onSave(fn: () => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
**@since v1.1.7**
================================================
FILE: docs/docs/api/plugins.md
================================================
---
title: plugins - 插件 API
sidebar_position: 2
---
> **@types** [IPublicApiPlugins](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/plugins.ts)
> **@since** v1.0.0
## 模块简介
插件管理器,提供编排模块中管理插件的能力。
## 方法
### register
注册插件
```typescript
async function register(
plugin: IPublicTypePlugin,
options?: IPublicTypePluginRegisterOptions,
): Promise
```
相关 types:
- [IPublicTypePlugin](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin.ts)
- [IPublicTypePluginRegisterOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-register-options.ts)
其中第一个参数 plugin 通过低代码工具链的插件脚手架生成编写模板,开发者可以参考[这个章节](/site/docs/guide/expand/editor/cli)进行创建
#### 简单示例
```typescript
import { plugins } from '@alilc/lowcode-engine';
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
const builtinPluginRegistry = (ctx: IPublicModelPluginContext) => {
return {
async init() {
const { skeleton } = ctx;
// 注册组件面板
const componentsPane = skeleton.add({
area: 'leftArea',
type: 'PanelDock',
name: 'componentsPane',
content: ComponentsPane,
contentProps: {},
props: {
align: 'top',
icon: 'zujianku',
description: '组件库',
},
});
componentsPane?.disable?.();
project.onSimulatorRendererReady(() => {
componentsPane?.enable?.();
})
},
};
}
builtinPluginRegistry.pluginName = 'builtinPluginRegistry';
await plugins.register(builtinPluginRegistry);
```
#### 使用 exports 示例
```typescript
import { plugins } from '@alilc/lowcode-engine';
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
const PluginA = (ctx: IPublicModelPluginContext) => {
return {
async init() {},
exports() { return { x: 1, } },
};
}
PluginA.pluginName = 'PluginA';
const PluginB = (ctx: IPublicModelPluginContext) => {
return {
async init() {
// 获取 pluginA 的导出值
console.log(ctx.plugins.PluginA.x); // => 1
},
};
}
PluginA.pluginName = 'pluginA';
PluginB.pluginName = 'PluginB';
PluginB.meta = {
dependencies: ['PluginA'],
}
await plugins.register(PluginA);
await plugins.register(PluginB);
```
> 注:ctx 是在插件中获取引擎 API 的唯一渠道,具体定义参见 [IPublicModelPluginContext](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-context.ts)
#### 设置兼容引擎版本示例
```typescript
import { plugins } from '@alilc/lowcode-engine';
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
const BuiltinPluginRegistry = (ctx: IPublicModelPluginContext) => {
return {
async init() {
...
},
};
}
BuiltinPluginRegistry.pluginName = 'BuiltinPluginRegistry';
BuiltinPluginRegistry.meta = {
engines: {
lowcodeEngine: '^1.0.0', // 插件需要配合 ^1.0.0 的引擎才可运行
},
}
await plugins.register(BuiltinPluginRegistry);
```
#### 设置插件参数版本示例
```typescript
import { plugins } from '@alilc/lowcode-engine';
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
const BuiltinPluginRegistry = (ctx: IPublicModelPluginContext, options: any) => {
return {
async init() {
// 直接传值方式:
// 通过 register(xxx, options) 传入
// 通过 options 取出
// 引擎初始化时也可以设置某插件的全局配置项:
// 通过 engine.init(..., preference) 传入
// 通过 ctx.preference.getValue() 取出
},
};
}
BuiltinPluginRegistry.pluginName = 'BuiltinPluginRegistry';
BuiltinPluginRegistry.meta = {
preferenceDeclaration: {
title: 'pluginA 的参数定义',
properties: [
{
key: 'key1',
type: 'string',
description: 'this is description for key1',
},
{
key: 'key2',
type: 'boolean',
description: 'this is description for key2',
},
{
key: 'key3',
type: 'number',
description: 'this is description for key3',
},
{
key: 'key4',
type: 'string',
description: 'this is description for key4',
},
],
},
}
await plugins.register(BuiltinPluginRegistry, { key1: 'abc', key5: 'willNotPassToPlugin' });
```
### get
获取指定插件
```typescript
/**
* 获取指定插件
* get plugin instance by name
*/
get(pluginName: string): IPublicModelPluginInstance | null;
```
关联模型 [IPublicModelPluginInstance](./model/plugin-instance)
### getAll
获取所有的插件实例
```typescript
/**
* 获取所有的插件实例
* get all plugin instances
*/
getAll(): IPublicModelPluginInstance[];
```
关联模型 [IPublicModelPluginInstance](./model/plugin-instance)
### has
判断是否有指定插件
```typescript
/**
* 判断是否有指定插件
* check if plugin with certain name exists
*/
has(pluginName: string): boolean;
```
### delete
删除指定插件
```typescript
/**
* 删除指定插件
* delete plugin instance by name
*/
delete(pluginName: string): void;
```
### getPluginPreference
引擎初始化时可以提供全局配置给到各插件,通过这个方法可以获得本插件对应的配置
```typescript
/**
* 引擎初始化时可以提供全局配置给到各插件,通过这个方法可以获得本插件对应的配置
* use this to get preference config for this plugin when engine.init() called
*/
getPluginPreference(
pluginName: string,
): Record | null | undefined;
```
## 相关类型定义
- [IPublicModelPluginContext](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-context.ts)
- [IPublicTypePluginConfig](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/plugin-config.ts)
- [IPublicModelPluginInstance](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/plugin-instance.ts)
## 插件元数据工程转化示例
your-plugin/package.json
```json
{
"name": "@alilc/lowcode-plugin-debug",
"lcMeta": {
"pluginName": "debug",
"meta": {
"engines": {
"lowcodeEgnine": "^1.0.0"
},
"preferenceDeclaration": { ... }
}
}
}
```
转换后的结构:
```typescript
const debug = (ctx: IPublicModelPluginContext, options: any) => {
return {};
}
debug.pluginName = 'debug';
debug.meta = {
engines: {
lowcodeEgnine: '^1.51.0',
},
preferenceDeclaration: { ... }
};
```
================================================
FILE: docs/docs/api/project.md
================================================
---
title: project - 模型 API
sidebar_position: 10
---
## 模块简介
引擎编排模块中包含多种模型,包括:
- [文档模型 DocumentModel](./model/document-model)
- [节点模型 Node](./model/node)
- [节点孩子模型 NodeChildren](./model/node-children)
- [属性模型 Prop](./model/prop)
- [属性集模型 Props](./model/props)
他们的依赖关系如下图:

在文档模型内部,又有一些引申模型,比如:
- [历史操作 History)](./model/history)
- [画布节点选中 Selection)](./model/selection)
- [画布节点悬停 Detecting)](./model/detecting)
- [模态节点管理器 ModalNodesManager](./model/modal-nodes-manager)
整个模型系统,以 project API 为入口,所有模型实例均需要通过 project 来获得,比如 project.currentDocument 来获取当前的文档模型,project.currentDocument.nodesMap 来获取当前文档模型里所有的节点列表。
下面来看看 project API 的具体介绍
## 变量
### currentDocument
获取当前的 document 实例
```typescript
/**
* 获取当前的 document
* get current document
*/
get currentDocument(): IPublicModelDocumentModel | null;
```
相关类型:[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)
### documents
获取当前 project 下所有 documents
```typescript
/**
* 获取当前 project 下所有 documents
* get all documents of this project
* @returns
*/
get documents(): IPublicModelDocumentModel[];
```
相关类型:[IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)
### simulatorHost
获取模拟器的 host
```typescript
/**
* 获取模拟器的 host
* get simulator host
*/
get simulatorHost(): IPublicApiSimulatorHost | null;
```
相关类型:[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
## 方法
### openDocument
打开一个 document
```typescript
/**
* 打开一个 document
* @param doc
* @returns
*/
openDocument(doc?: string | IPublicTypeRootSchema | undefined): IPublicModelDocumentModel | null;
```
相关类型:
- [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)
### createDocument
创建一个 document
```typescript
/**
* 创建一个 document
* create a document
* @param data
* @returns
*/
createDocument(data?: IPublicTypeRootSchema): IPublicModelDocumentModel | null;
```
相关类型:
- [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
- [IPublicTypeRootSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/root-schema.ts)
### removeDocument
删除一个 document
```typescript
/**
* 删除一个 document
* remove a document
* @param doc
*/
removeDocument(doc: IPublicModelDocumentModel): void;
```
相关类型:[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
### getDocumentByFileName
根据 fileName 获取 document
```typescript
/**
* 根据 fileName 获取 document
* get a document by filename
* @param fileName
* @returns
*/
getDocumentByFileName(fileName: string): IPublicModelDocumentModel | null;
```
相关类型:[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
### getDocumentById
根据 id 获取 document
```typescript
/**
* 根据 id 获取 document
* get a document by id
* @param id
* @returns
*/
getDocumentById(id: string): IPublicModelDocumentModel | null;
```
相关类型:[IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
### exportSchema
导出 project schema
```typescript
/**
* 导出 project
* export project to schema
* @returns
*/
exportSchema(stage: IPublicEnumTransformStage): IPublicTypeProjectSchema;
```
相关类型:
- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)
- [IPublicTypeProjectSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/project-schema.ts)
### importSchema
导入 project
```typescript
/**
* 导入 project schema
* import schema to project
* @param schema 待导入的 project 数据
*/
importSchema(schema?: IPublicTypeProjectSchema): void;
```
相关类型:[IPublicTypeProjectSchema](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/project-schema.ts)
### addPropsTransducer
增加一个属性的管道处理函数
```typescript
/**
* 增加一个属性的管道处理函数
* add a transducer to process prop
* @param transducer
* @param stage
*/
addPropsTransducer(
transducer: IPublicTypePropsTransducer,
stage: IPublicEnumTransformStage,
): void;
```
相关类型:
- [IPublicTypePropsTransducer](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/props-transducer.ts)
- [IPublicEnumTransformStage](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/enum/transform-stage.ts)
**示例**
在保存的时候删除每一个组件的 props.hidden
```typescript
import { project } from '@alilc/lowcode-engine';
import { IPublicTypeCompositeObject, IPublicEnumTransformStage, IPublicModelPluginContext } from '@alilc/lowcode-types';
export const DeleteHiddenTransducer = (ctx: IPublicModelPluginContext) => {
return {
async init() {
const { project } = ctx;
project.addPropsTransducer((props: IPublicTypeCompositeObject): IPublicTypeCompositeObject => {
delete props.hidden;
return props;
}, IPublicEnumTransformStage.Save);
},
};
}
DeleteHiddenTransducer.pluginName = 'DeleteHiddenTransducer';
```
### setI18n
设置多语言语料
```typescript
/**
* 设置多语言语料
* 数据格式参考 https://github.com/alibaba/lowcode-engine/blob/main/specs/lowcode-spec.md#2434%E5%9B%BD%E9%99%85%E5%8C%96%E5%A4%9A%E8%AF%AD%E8%A8%80%E7%B1%BB%E5%9E%8Baa
*
* set I18n data for this project
* @param value object
* @since v1.0.17
*/
setI18n(value: object): void;
```
**@since v1.0.17**
### setConfig
设置当前项目配置
```typescript
/**
* 设置当前项目配置
* set config for this project
* @param value object
* @since v1.1.4
*/
setConfig(value: IPublicTypeAppConfig): void;
setConfig(key: T, value: IPublicTypeAppConfig[T]): void;
```
**@since v1.1.4**
#### 如何扩展项目配置
```typescript
// shims.d.ts
declare module '@alilc/lowcode-types' {
export interface IPublicTypeAppConfig {
customProp: CustomPropType
}
}
export {};
```
## 事件
### onRemoveDocument
绑定删除文档事件
```typescript
/**
* 绑定删除文档事件
* set callback for event onDocumentRemoved
* @param fn
* @since v1.0.16
*/
onRemoveDocument(fn: (data: { id: string }) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
**@since v1.0.16**
### onChangeDocument
当前 project 内的 document 变更事件
```typescript
/**
* 当前 project 内的 document 变更事件
* set callback for event onDocumentChanged
*/
onChangeDocument(fn: (doc: IPublicModelDocumentModel) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicModelDocumentModel](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/model/document-model.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onSimulatorHostReady
当前 project 的模拟器 ready 事件
```typescript
/**
* 当前 project 的模拟器 ready 事件
* set callback for event onSimulatorHostReady
*/
onSimulatorHostReady(fn: (host: IPublicApiSimulatorHost) => void): IPublicTypeDisposable;
```
相关类型:
- [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
- [IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onSimulatorRendererReady
当前 project 的渲染器 ready 事件
```typescript
/**
* 当前 project 的渲染器 ready 事件
* set callback for event onSimulatorRendererReady
*/
onSimulatorRendererReady(fn: () => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
================================================
FILE: docs/docs/api/setters.md
================================================
---
title: setters - 设置器 API
sidebar_position: 10
---
> **@types** [IPublicApiSetters](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/setters.ts)
> **@since** v1.0.0
## 模块简介
负责注册设置器、管理设置器的 API。注册自定义设置器之后可以在物料中进行使用。
## 方法
### getSetter
获取指定 setter
```typescript
/**
* 获取指定 setter
* get setter by type
* @param type
* @returns
*/
getSetter(type: string): IPublicTypeRegisteredSetter | null;
```
相关类型:[IPublicTypeRegisteredSetter](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/registerd-setter.ts)
### getSettersMap
获取已注册的所有 settersMap
```typescript
/**
* 获取已注册的所有 settersMap
* get map of all registered setters
* @returns
*/
getSettersMap(): Map;
```
相关类型:[IPublicTypeRegisteredSetter](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/registerd-setter.ts)
### registerSetter
注册一个 setter
```typescript
/**
* 注册一个 setter
* register a setter
* @param typeOrMaps
* @param setter
* @returns
*/
registerSetter(
typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter },
setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter | undefined
): void;
```
相关类型:
- [IPublicTypeRegisteredSetter](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/registerd-setter.ts)
- [IPublicTypeCustomView](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/custom-view.ts)
## 使用示例
### 注册官方内置 Setter 到设计器中
```typescript
import { setters, skeleton } from '@alilc/lowcode-engine';
import { setterMap, pluginMap } from '@alilc/lowcode-engine-ext';
import { IPublicModelPluginContext } from '@alilc/lowcode-types';
const SetterRegistry = (ctx: IPublicModelPluginContext) => {
return {
name: 'ext-setters-registry',
async init() {
// 注册 setterMap
setters.registerSetter(setterMap);
// 注册插件
// 注册事件绑定面板
skeleton.add({
area: 'centerArea',
type: 'Widget',
content: pluginMap.EventBindDialog,
name: 'eventBindDialog',
props: {},
});
// 注册变量绑定面板
skeleton.add({
area: 'centerArea',
type: 'Widget',
content: pluginMap.VariableBindDialog,
name: 'variableBindDialog',
props: {},
});
},
};
}
SetterRegistry.pluginName = 'SetterRegistry';
await plugins.register(SetterRegistry);
```
### 开发自定义 Setter
AltStringSetter 代码如下:
```typescript
import * as React from "react";
import { Input } from "@alifd/next";
import "./index.scss";
interface AltStringSetterProps {
// 当前值
value: string;
// 默认值
initialValue: string;
// setter 唯一输出
onChange: (val: string) => void;
// AltStringSetter 特殊配置
placeholder: string;
}
export default class AltStringSetter extends React.PureComponent {
componentDidMount() {
const { onChange, value, defaultValue } = this.props;
if (value == undefined && defaultValue) {
onChange(defaultValue);
}
}
// 声明 Setter 的 title
static displayName = 'AltStringSetter';
render() {
const { onChange, value, placeholder } = this.props;
return (
onChange(val)}
>
);
}
}
```
开发完毕之后,注册 AltStringSetter 到设计器中:
```typescript
import AltStringSetter from './AltStringSetter';
import { setters } from '@alilc/lowcode-engine';
const { registerSetter } = setters;
registerSetter('AltStringSetter', AltStringSetter);
```
注册之后,我们就可以在物料中使用了,其中核心配置如下:
```typescript
{
"props": {
"isExtends": true,
"override": [
{
"name": "type",
"setter": "AltStringSetter"
}
]
}
}
```
完整配置如下:
```typescript
{
"componentName": "Message",
"title": "Message",
"props": [
{
"name": "title",
"propType": "string",
"description": "标题",
"defaultValue": "标题"
},
{
"name": "type",
"propType": {
"type": "oneOf",
"value": [
"success",
"warning",
"error",
"notice",
"help",
"loading"
]
},
"description": "反馈类型",
"defaultValue": "success"
}
],
"configure": {
"props": {
"isExtends": true,
"override": [
{
"name": "type",
"setter": "AltStringSetter"
}
]
}
}
}
```
================================================
FILE: docs/docs/api/simulatorHost.md
================================================
---
title: simulatorHost - 模拟器 API
sidebar_position: 10
---
> **@types** [IPublicApiSimulatorHost](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/simulator-host.ts)
> **@since** v1.0.0
## 模块简介
负责模拟器相关的 API,包括画布尺寸、语言等。
## 方法
### set
设置 host 配置值
```typescript
/**
* 设置若干用于画布渲染的变量,比如画布大小、locale 等。
* set config for simulator host, eg. device locale and so on.
* @param key
* @param value
*/
set(key: string, value: any): void;
```
**示例**
设置若干用于画布渲染的变量,比如画布大小、locale 等。
以设置画布大小为例:
目前支持 3 种定制方式:
```typescript
// 直接使用内置设备类型
project.simulatorHost.set('device', 'mobile' / 'iphonex' / 'iphone6' / 'default');
// 定制 canvas 的样式类
project.simulatorHost.set('deviceClassName', 'my-canvas-class');
// 最灵活的方式,直接设置 canvas / viewport 的样式(canvas 是外框,viewport 是内框,可以在 canvas 设置手机 / 平板背景图)
project.simulatorHost.set('deviceStyle', { canvas: { width: '300px', backgroundColor: 'red' }, viewport: { width: '280px' } });
```
### get
获取模拟器中设置的变量,比如画布大小、locale 等。
```typescript
/**
* 获取模拟器中设置的变量,比如画布大小、locale 等。
* set config value by key
* @param key
* @returns
*/
get(key: string): any;
```
### rerender
触发组件构建,并刷新渲染画布
```typescript
/**
* 触发组件构建,并刷新渲染画布
* make simulator render again
*/
rerender(): void;
```
### scrollToNode
滚动到指定节点
```typescript
/**
* 滚动到指定节点
* scroll to specific node
* @param node
* @since v1.1.0
*/
scrollToNode(node: IPublicModelNode): void;
```
**@since v1.1.0**
================================================
FILE: docs/docs/api/skeleton.md
================================================
---
title: skeleton - 面板 API
sidebar_position: 10
---
> **@types** [IPublicApiSkeleton](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/skeleton.ts)
> **@since** v1.0.0
## 模块简介
面板 API 提供了面板扩展和管理的能力,如下图蓝色内容都是扩展出来的。

页面上可以扩展的区域共 5 个,具体如下:

### 基本概念
#### 扩展区域位置 (area)
##### topArea
展示在设计器的顶部区域,常见的相关区域的插件主要是:
1. 注册设计器 Logo;
2. 设计器操作回退和撤销按钮;
3. 全局操作按钮,例如:保存、预览等;
##### leftArea
左侧区域的展示形式大多数是 Icon 和对应的面板,通过点击 Icon 可以展示对应的面板并隐藏其他的面板。
该区域相关插件的主要有:
1. 大纲树展示,展示该设计器设计页面的大纲。
2. 组件库,展示注册到设计器中的组件,点击之后,可以从组件库面板中拖拽到设计器的画布中。
3. 数据源面板
4. JS 等代码面板。
可以发现,这个区域的面板大多数操作时是不需要同时并存的,且交互比较复杂的,需要一个更整块的区域来进行操作。
##### centerArea
画布区域,由于画布大多数是展示作用,所以一般扩展的种类比较少。常见的扩展有:
1. 画布大小修改
2. 物料选中扩展区域修改
##### rightArea
右侧区域,常用于组件的配置。常见的扩展有:统一处理组件的配置项,例如统一删除某一个配置项,统一添加某一个配置项的。
##### toolbar
跟 topArea 类似,按需放置面板插件~
#### 展示类型 (type)
展示类型用于区分插件在设计器内可操作的几种不同界面类型。主要的几种类型为 PanelDock、Widget、Dock,另有 Panel 类型目前不推荐使用。
##### PanelDock
PanelDock 是以面板的形式展示在设计器的左侧区域的。其中主要有两个部分组成,一个是图标,一个是面板。当点击图标时可以控制面板的显示和隐藏。
下图是组件库插件的展示效果。

其中右上角可以进行固定,可以对弹出的宽度做设定
接入可以参考代码
```javascript
import { skeleton } from "@alilc/lowcode-engine";
skeleton.add({
area: "leftArea", // 插件区域
type: "PanelDock", // 插件类型,弹出面板
name: "sourceEditor",
content: SourceEditor, // 插件组件实例
props: {
align: "left",
icon: "wenjian",
title: '标题', // 图标下方展示的标题
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');
}
}
});
```
## 方法
### add
往指定扩展区加入一块面板
```typescript
/**
* 增加一个面板实例
* add a new panel
* @param config
* @param extraConfig
* @returns
*/
add(config: IPublicTypeWidgetBaseConfig, extraConfig?: Record): any;
```
IWidgetBaseConfig 定义如下:
| 属性名 | 含义 | 备注 |
| --- | --- | --- |
| name | 面板名称 | |
| area | 扩展区位置,可选值:'topArea' | 'leftArea' | 'rightArea' | 'toolbar' | 'bottomArea' | 'mainArea' | |
| type | 面板类型,可选值:'Widget' | 'PanelDock' | 'Panel' | Dock | 详见前文中对**展示类型**的描述 |
| content | 面板的实现类/节点,类型是 ReactClass | ReactElement | |
| props | 面板属性 | align: 'top' | 'bottom' | 'left' | 'center' | 'right'; // 指定面板 icon 位置区域
icon: string | ReactElement; // icon 为字符串时,请确定当前 fusion 主题包中包含该 icon
description: string;
condition: Function; // 指定当前面板的显影状态 |
| contentProps | 面板的实现类/节点的参数 | |
| panelProps | 假如 type: 'Panel' | 'PanelDock' 时有效,传给 Panel 类的参数 | keepVisibleWhileDragging: boolean; // 当有元素在当前 panel 拖拽时,是否保持 panel 为展开状态,默认值:false
area: 'leftFloatArea' | 'leftFixedArea' // 指定 panel 位于浮动面板还是钉住面板 |
| index | 面板的位置,不传默认按插件注册顺序 | |
### remove
移除一个面板实例
```typescript
/**
* 移除一个面板实例
* remove a panel
* @param config
* @returns
*/
remove(config: IPublicTypeWidgetBaseConfig): number | undefined;
```
### getPanel
获取面板实例
```typescript
/**
* 获取面板实例
* @param name 面板名称
*/
getPanel(name: string): IPublicModelSkeletonItem | undefined;
```
相关类型:[IPublicModelSkeletonItem](https://github.com/alibaba/lowcode-engine/blob/main/packages/shell/src/model/skeleton-item.ts)
@since v1.1.10
### showPanel
展示指定 Panel 实例
```typescript
/**
* 展示指定 Panel 实例
* show panel by name
* @param name
*/
showPanel(name: string): void;
```
### hidePanel
隐藏面板
```typescript
/**
* 隐藏面板
* hide panel by name
* @param name
*/
hidePanel(name: string): void;
```
### showWidget
展示指定 Widget 实例
```typescript
/**
* 展示指定 Widget 实例
* show widget by name
* @param name
*/
showWidget(name: string): void;
```
### enableWidget
将 widget 启用。
```typescript
/**
* 将 widget 启用
* enable widget
* @param name
*/
enableWidget(name: string): void;
```
### hideWidget
隐藏指定 widget 实例。
```typescript
/**
* 隐藏指定 widget 实例
* hide widget by name
* @param name
*/
hideWidget(name: string): void;
```
### disableWidget
将 widget 禁用掉,禁用后,所有鼠标事件都会被禁止掉。
适用场景:在该面板还在进行初始化构造时,可以先禁止掉,防止用户点击报错,待初始化完成,重新启用。
```typescript
/**
* 将 widget 禁用掉,禁用后,所有鼠标事件都会被禁止掉。
* disable widget,and make it not responding any click event.
* @param name
*/
disableWidget(name: string): void;
```
### showArea
显示某个 Area
```typescript
/**
* 显示某个 Area
* show area
* @param areaName name of area
*/
showArea(areaName: string): void;
```
### hideArea
隐藏某个 Area
```typescript
/**
* 隐藏某个 Area
* hide area
* @param areaName name of area
*/
hideArea(areaName: string): void;
```
### getAreaItems
获取某个区域下的所有面板实例
```typescript
/**
* 获取某个区域下的所有面板实例
* @param areaName IPublicTypeWidgetConfigArea
*/
getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] | undefined;
```
相关类型:[IPublicModelSkeletonItem](https://github.com/alibaba/lowcode-engine/blob/main/packages/shell/src/model/skeleton-item.ts)
### registerConfigTransducer
注册一个面板的配置转换器(transducer)。
```typescript
/**
* 注册一个面板的配置转换器(transducer)。
* Registers a configuration transducer for a panel.
* @param {IPublicTypeConfigTransducer} transducer
* - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。
* - The transducer function to be registered. This function takes a configuration object
*
* @param {number} level
* - 转换器的优先级。优先级较高的转换器会先执行。
* - The priority level of the transducer. Transducers with higher priority levels are executed first.
*
* @param {string} [id]
* - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。
* - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed.
*/
registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void;
```
使用示例
```typescript
import { IPublicModelPluginContext, IPublicTypeSkeletonConfig } from '@alilc/lowcode-types';
function updatePanelWidth(config: IPublicTypeSkeletonConfig) {
if (config.type === 'PanelDock') {
return {
...config,
panelProps: {
...(config.panelProps || {}),
width: 240,
},
}
}
return config;
}
const controlPanelWidthPlugin = (ctx: IPublicModelPluginContext) => {
const { skeleton } = ctx;
(skeleton as any).registerConfigTransducer?.(updatePanelWidth, 1, 'update-panel-width');
return {
init() {},
};
};
controlPanelWidthPlugin.pluginName = 'controlPanelWidthPlugin';
controlPanelWidthPlugin.meta = {
dependencies: [],
engines: {
lowcodeEngine: '^1.2.3', // 插件需要配合 ^1.0.0 的引擎才可运行
},
};
export default controlPanelWidthPlugin;
```
## 事件
### onShowPanel
监听 Panel 实例显示事件
```typescript
/**
* 监听 panel 显示事件
* set callback for panel shown event
* @param listener
* @returns
*/
onShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onHidePanel
监听 Panel 实例隐藏事件
```typescript
/**
* 监听 Panel 实例隐藏事件
* set callback for panel hidden event
* @param listener
* @returns
*/
onHidePanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onDisableWidget
监听 Widget 实例 Disable 事件
```typescript
/**
* 监听 Widget 实例 Disable 事件
* @param listener
*/
onDisableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onEnableWidget
监听 Widget 实例 Enable 事件
```typescript
/**
* 监听 Widget 实例 Enable 事件
* @param listener
*/
onEnableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onShowWidget
监听 Widget 实例显示事件
```typescript
/**
* 监听 Widget 显示事件
* set callback for widget shown event
* @param listener
* @returns
*/
onShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onHideWidget
监听 Widget 实例隐藏事件
```typescript
/**
* 监听 Widget 隐藏事件
* set callback for widget hidden event
* @param listener
* @returns
*/
onHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
## 使用示例
```typescript
import { skeleton } from '@alilc/lowcode-engine';
skeleton.add({
name: 'logo',
area: 'topArea',
type: 'Widget',
contentProps: {},
content: LogoContent,
});
skeleton.add({
name: 'sourceEditor',
type: 'PanelDock',
area: 'leftArea',
props: {
align: 'top',
icon: 'wenjian',
description: 'JS 面板',
},
panelProps: {
floatable: true,
height: 300,
help: undefined,
hideTitleBar: false,
maxHeight: 800,
maxWidth: 1200,
title: 'JS 面板',
width: 600,
},
content: SourceEditor,
});
// 显隐 panel
skeleton.showPanel('sourceEditor');
skeleton.hidePanel('sourceEditor');
// 创建一个浮动的 widget
skeleton.add({
name: 'floatingWidget',
type: 'Widget',
area: 'mainArea',
props: {},
content: React.createElement('div', {}, 'haha'),
contentProps: {
style: {
position: 'fixed',
top: '200px',
bottom: 0,
width: 'calc(100% - 46px)',
'background-color': 'lightblue'
}
}
});
// 显隐 widget
skeleton.showWidget('floatingWidget');
skeleton.hideWidget('floatingWidget');
// 控制 widget 的可点击态
skeleton.enableWidget('sourceEditor');
skeleton.disableWidget('sourceEditor');
```
### bottomArea 示例
```typescript
import { skeleton } from '@alilc/lowcode-engine';
skeleton.add({
name: 'bottomAreaPanelName',
area: 'bottomArea',
type: 'Panel',
content: () => 'demoText',
});
skeleton.showPanel('bottomAreaPanelName');
```
### widget 示例
```typescript
// 注册 logo 面板
skeleton.add({
area: 'topArea',
type: 'Widget',
name: 'logo',
content: Logo,
contentProps: {
logo: 'https://img.alicdn.com/imgextra/i4/O1CN013w2bmQ25WAIha4Hx9_!!6000000007533-55-tps-137-26.svg',
href: 'https://lowcode-engine.cn',
},
props: {
align: 'left',
},
});
```
================================================
FILE: docs/docs/api/workspace.md
================================================
---
title: workspace - 应用级 API
sidebar_position: 10
---
> **[@experimental](./#experimental)**
> **@types** [IPublicApiWorkspace](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/api/workspace.ts)
> **@since** v1.1.0
## 模块简介
通过该模块可以开发应用级低代码设计器。
## 变量
### isActive
是否启用 workspace 模式
### window
当前设计器窗口模型
```typescript
get window(): IPublicModelWindow
```
关联模型 [IPublicModelWindow](./model/window)
### plugins
应用级别的插件注册
```typescript
get plugins(): IPublicApiPlugins
```
关联模型 [IPublicApiPlugins](./plugins)
### skeleton
应用级别的面板管理
```typescript
get skeleton(): IPublicApiSkeleton
```
关联模型 [IPublicApiSkeleton](./skeleton)
### windows
当前设计器的编辑窗口
```typescript
get window(): IPublicModelWindow[]
```
关联模型 [IPublicModelWindow](./model/window)
### resourceList
当前设计器的资源列表数据
```
get resourceList(): IPublicModelResource;
```
关联模型 [IPublicModelResource](./model/resource)
## 方法
### registerResourceType
注册资源
```typescript
/** 注册资源 */
registerResourceType(resourceTypeModel: IPublicTypeResourceType): void;
```
相关类型:[IPublicTypeResourceType](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-type.ts)
### setResourceList
设置设计器资源列表数据
```typescript
setResourceList(resourceList: IPublicResourceList) {}
```
相关类型:[IPublicResourceData](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-list.ts)
### openEditorWindow
打开视图窗口
```typescript
/**
* 打开视图窗口
* @deprecated
*/
openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise;
/** 打开视图窗口 */
openEditorWindow(resource: Resource, sleep?: boolean): Promise;
```
### openEditorWindowById
通过视图 id 打开窗口
```typescript
openEditorWindowById(id: string): void;
```
### removeEditorWindow
移除视图窗口
```typescript
/**
* 移除视图窗口
* @deprecated
*/
removeEditorWindow(resourceName: string, id: string): void;
/**
* 移除视图窗口
*/
removeEditorWindow(resource: Resource): void;
```
### removeEditorWindowById
通过视图 id 移除窗口
```typescript
removeEditorWindowById(id: string): void;
```
## 事件
### onChangeWindows
窗口新增/删除的事件
```typescript
function onChangeWindows(fn: () => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onChangeActiveWindow
active 窗口变更事件
```typescript
function onChangeActiveWindow(fn: () => void): IPublicTypeDisposable;
```
相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
### onResourceListChange
设计器资源列表数据变更事件
```typescript
onResourceListChange(fn: (resourceList: IPublicResourceList): void): (): IPublicTypeDisposable;
```
- 相关类型:[IPublicResourceOptions](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/resource-options.ts)
- 相关类型:[IPublicTypeDisposable](https://github.com/alibaba/lowcode-engine/blob/main/packages/types/src/shell/type/disposable.ts)
================================================
FILE: docs/docs/article/index.md
================================================
# 官方文章
- [2023/11/09 UIPaaS | 基于 LowCodeEngine 的低代码平台孵化器](https://mp.weixin.qq.com/s/mKuv3_Wvgt5T3AGErUGBQQ)
- [2023/04/04 什么?低代码引擎可以开发应用了](https://mp.weixin.qq.com/s/dwi40gJjGBHW9MVpag5Oxg)
- [2023/03/23 低代码引擎 LowCodeEngine 茁壮成长的一年](https://mp.weixin.qq.com/s/DDt4LQLFUBQ2-F5ehZGBKg)
- [2023/02/21 基于 LowCodeEngine 的低代码组件体系的建设和实践](https://mp.weixin.qq.com/s/rnvbGHImGt6oJuX2wCtaqw)
- [2022/12/21 低代码多分支协同开发的建设与实践](https://mp.weixin.qq.com/s/DmwxL67htHfTUP1U966N-Q)
- [2022/11/24 低代码引擎半岁啦,来跟大家唠唠嗑...](https://segmentfault.com/a/1190000042884409)
- [2022/10/27 低代码技术在研发团队的应用模式探讨](https://mp.weixin.qq.com/s/Ynk_wjJbmNw7fEG6UtGZbQ)
- [2022/08/23 基于 LowCodeEngine 的调试能力建设与实践](https://mp.weixin.qq.com/s/H8KvEOylmzLPgIuuBO0S9w)
- [2022/06/23 低代码渲染那些事](https://mp.weixin.qq.com/s/yqYey76qLGYPfDtpGkVFfA)
- [2022/06/16 关于 LowCode&ProCode 混合研发的思考](https://mp.weixin.qq.com/s/TY3VXjkSmsQoT47xma3wig)
- [2022/04/07 磁贴布局在钉钉宜搭报表设计引擎中的实现](https://mp.weixin.qq.com/s/PSTut5ahAB8nlJ9kBpBaxw)
- [2022/03/23 阿里低代码引擎 LowCodeEngine 正式开源!](https://mp.weixin.qq.com/s/T66LghtWLz2Oh048XqaniA)
- [2022/01/10 阿里低代码引擎和生态建设实战及思考](https://mp.weixin.qq.com/s/MI6MrUKKydtnSdO4xq6jwA)
- [2021/04/14 2B 领域下的低代码探索之路](https://mp.weixin.qq.com/s/HAxrMHLT43dPH488RiEIdw)
================================================
FILE: docs/docs/demoUsage/advanced/_category_.json
================================================
{
"label": "进阶功能",
"position": 3,
"collapsed": false,
"collapsible": false
}
================================================
FILE: docs/docs/demoUsage/advanced/hotkey.md
================================================
---
title: 8. 编辑器快捷键
sidebar_position: 0
---
- 任意时机:
- `⌘` `S` 保存
- `⌘` `P` 预览
- `⌘` `D` 查看 Diff
- `⌘` `Z` 撤销
- `⇧` `⌘` `Z` 重做
- 选择任意组件后:
- `Backspace` 删除组件
- `⌘` `C` 复制组件
- `⌘` `V` 粘贴组件
- `⌘` `X` 剪切组件
- `⌥` `↑` 向外层移动组件
- `⌥` `↓` 向内层移动组件
- `⌥` `←` 同级向上移动组件
- `⌥` `→` 同级向下移动组件
- `↑` 向上选择组件
- `↓` 向下选择组件
- `←` 向左选择组件
- `→` 向右选择组件
- `Escape` 取消选择组件
================================================
FILE: docs/docs/demoUsage/appendix/_category_.json
================================================
{
"label": "常见问题",
"position": 4,
"collapsed": false,
"collapsible": false
}
================================================
FILE: docs/docs/demoUsage/appendix/api.md
================================================
---
title: demo 使用相关 API
sidebar_position: 2
---
## 数据源相关
### 请求数据源
```javascript
// 请求 userList(userList 在数据源面板中定义)
this.dataSourceMap['userList'].load({
data: {}
}).then(res => {})
.catch(error => {});
```
### 获取数据源的值
```javascript
const { userList } = this.state;
```
### 手动修改数据源值
```javascript
// 获取数据源面板中定义的值
const { user } = this.state;
// 修改 state 值
this.setState({
user: {}
});
```
================================================
FILE: docs/docs/demoUsage/appendix/loop.md
================================================
---
title: 如何使用循环值
sidebar_position: 0
---
1.设置循环数据

2.给需要的变量绑定 this.item

绑定之后的效果如下:

其中 this.item 的 item 是可以配置的。配置不同的 key 可以方便在多层循环中使用不同层级的循环 item 值。

this.index 是当前循环的索引值。
3.在事件绑定函数中使用
在事件绑定函数中使用扩展参数设置

绑定之后在函数中使用

按钮点击效果

================================================
FILE: docs/docs/demoUsage/intro.md
================================================
---
title: 1. 试用低代码引擎 Demo
sidebar_position: 0
---
低代码编辑器中的区块主要包含这些功能点:

## 分区块功能介绍
### 左侧:面板与操作区
#### 物料面板
可以查找组件,并在此拖动组件到编辑器画布中

#### 大纲面板
可以调整页面内的组件树结构:

可以在这里打开或者关闭模态浮层的展现:

#### 源码面板
可以编辑页面级别的 JavaScript 代码和 CSS 配置

#### Schema 编辑
【开发者专属】可以编辑页面的底层 Schema 数据。

搭配顶部操作区的“保存到本地”和“重置页面”功能,可以实验各种 schema 对低代码页面的改变。
它们操作的数据关系是:
- 页面中的 Schema 数据:保存在低代码引擎中的 Schema,点击 Schema 面板中的“保存 Schema”时将修改引擎中的值,此外低代码引擎中的所有操作都可能修改到 Schema
- localStorage 数据:由“保存到本地”保存到 localStorage 中,页面初始化时将读取,预览页面时也会读取
- 默认 Schema:保存在 Demo 项目中的默认 Schema(`public/schema.json`),初始化页面时如果不存在 localStorage 数据即会读取,点击“重置页面”时,也会读取
#### 中英文切换
可以切换编辑器的语言;注:需要组件配置配合。


## 中部:可视化页面编辑画布区域
点击组件在右侧面板中能够显示出对应组件的属性配置选项

拖拽修改组件的排列顺序

将组件拖拽到容器类型的组件中,注意拖拽时会在右侧提示当前的组件树。

## 右侧:组件级别配置
### 选中的组件
从页面开始一直到当前选中的组件位置,点击对应的名称可以切换到对应的组件上。

### 选中组件的配置
当前组件的大类目选项,根据组件类型不同,包含如下子类目:
#### 属性
组件的基础属性值设置

#### 样式
组件的样式配置,如文字:

#### 事件
绑定组件对外暴露的事件。

#### 高级
循环、条件渲染与 key 设置。

## 顶部:操作区
### 撤回和重做

================================================
FILE: docs/docs/demoUsage/makeStuff/_category_.json
================================================
{
"label": "如何制作",
"position": 1,
"collapsed": false,
"collapsible": false
}
================================================
FILE: docs/docs/demoUsage/makeStuff/dialog.md
================================================
---
title: 3. 如何通过按钮展示/隐藏弹窗
sidebar_position: 1
---
> 说明:这个方式依赖低代码弹窗组件是否对外保留了相关的 API,不同的物料支持的方式不一样,这里只针对综合场景的弹窗物料。
## 1.拖拽一个按钮

## 2.拖拽一个弹窗

## 3.查看弹窗 refId

- 点击弹窗
- 点击右侧面板中的高级
- 找到 refId

这里我们的 refId 是 "pro-dialog-entryl32xgrus"
## 4.隐藏弹窗
点击工具栏的隐藏小图标,将弹窗在画布中隐藏

## 5.按钮绑定事件

**通过下面的代码即可打开弹窗**
```typescript
this.$('pro-dialog-entryl32xgrus').open();
```
####
================================================
FILE: docs/docs/demoUsage/makeStuff/table.md
================================================
---
title: 2. 如何制作表格
sidebar_position: 0
---
## 步骤详解
### 拖入组件
一个常见的表格页面会包含查询框、表格和分页按钮。这些都在 Fusion UI 中进行了相应的封装,我们可以在左侧组件面板处找到他们。

将他们拖到画布之中:

### 配置组件
选中刚拖入的“查询筛选”组件,您可以配置此组件:

对于形如 Array 的配置项目,我们可以增删项目、修改常用项、修改顺序。

掌握组件配置功能,我们就可以完成一个常用的查询框的配置:

### 绑定数据
低代码场景下,我们需要绑定动态的数据。通过左侧的源码编辑面板,我们可以创建动态数据和它的相关处理函数:

如图,我们配入如下自定义值进 state 里:
```json
"companies": [
{ company: '测试公司1', id: 1, createTime: +new Date() },
{ company: '测试公司2', id: 2, createTime: +new Date() },
{ company: '测试公司3', id: 3, createTime: +new Date() },
]
```
定义动态数据以后,我们需要绑定它到组件的属性中,我们找到相关属性的配置:


如图,输入表达式:
```javascript
this.state.companies
```
再结合上一节的“配置组件”操作,我们已经可以把表格的主体配置出来了:

### 动态请求
我们进入代码区块,使用生命周期方法来完成动态数据的请求。假设提供数据的接口是:[http://rap2api.taobao.org/app/mock/250089/testCompanies](http://rap2api.taobao.org/app/mock/250089/testCompanies),那么,我们可以在源码面板进行如下配置:
```typescript
class LowcodeComponent extends Component {
state = {
"text": "outer",
"isShowDialog": false,
"loading": false,
"companies": [
{ company: '测试公司 1', id: 1, createTime: +new Date() },
{ company: '测试公司 2', id: 2, createTime: +new Date() },
{ company: '测试公司 3', id: 3, createTime: +new Date() },
]
}
componentDidMount() {
this.setState({ loading: true })
window.fetch('http://rap2api.taobao.org/app/mock/250089/testCompanies')
.then((res) => res.json())
.then((companies) => {
this.setState({
companies,
})
})
.catch(err => console.error(err))
.then(() => {
this.setState({ loading: false })
})
}
}
```
在 `componentDidMount` 生命周期,将请求接口并设置 loading 和数据字段。
点击保存或叉关闭源码面板后,我们可以看到代码已经生效了:

### 配置插槽
我们可以用绑定数据的方法把 loading 绑在加载指示上:


将 Loading 的“是否显示”字段绑定 `this.state.loading` 后,我们可以看到,这里暴露了一个插槽。插槽是可以任意扩展的预设部分,我们可以把其他的部分拖进插槽:

点击右上角的预览,我们能够看到完整的动态请求效果了:

### 列挂钩浮层
为了能够让表格里的操作挂钩浮层,我们先拖入一个浮层:

使用大纲树能够临时显示和隐藏此浮层:

我们给表格增加一个数据列:

然后配置它的行为为“弹窗”:

实现的效果如下:

### 事件回调
上述功能点中,我们是把操作行为绑定在数据列上的,这一节我们绑定到操作列中。在操作列按钮处,点击下方的“添加一项”:

点击左侧的详情按钮,配置它的事件回调:

代码侧,我们配置这个回调函数:
```javascript
onClick_new(e, { rowKey, rowIndex, rowRecord }){
window.Next.Message.show(JSON.stringify({ rowKey, rowIndex, rowRecord }))
}
```
保存。预览时我们可以看到效果了:

## 研究本例的 schema
我们把本例的 schema 保存在云端,您可以自行下载研究:[https://mo.m.taobao.com/marquex/lowcode-showcase-table](https://mo.m.taobao.com/marquex/lowcode-showcase-table)
您可以通过左下角的 Schema 面板直接导入本例子的 Schema。

================================================
FILE: docs/docs/demoUsage/panels/_category_.json
================================================
{
"label": "面板详解",
"position": 2,
"collapsed": false,
"collapsible": false
}
================================================
FILE: docs/docs/demoUsage/panels/canvas.md
================================================
---
title: 5. 画布详解
sidebar_position: 1
---
## 组件操作
### 画布操作
点击组件在右侧面板中能够显示出对应组件的属性配置选项

拖拽修改组件的排列顺序

拖拽时会在右侧提示当前的组件树。

### 组件控制
点击组件右上角的复制按钮,或者按下 `ctrl + c` 再按下 `ctrl + v`,可以将其复制;
点击组件右上角的删除按钮,或者直接使用 `Delete` 键,可以将其删除。

### 选择组件切换
可以用键盘上的按键切换组件选择:
- `↑` 向上选择组件
- `↓` 向下选择组件
- `←` 向左选择组件
- `→` 向右选择组件
可以 hover 到组件操作辅助区的第一项来选中组件的父级节点:

### 可扩展项简述
快捷键、操作辅助区均可扩展。
## Slot 区块
React 中,可以定义一个 prop 选项为 `JSXElement` 或 `(...args) => JSXElement` 的形式,这个形式在低代码画布中,被定义为 Slot,允许往其内部拖入组件,进行符合直觉的操作。

### 锁定 Slot
您可以对 Slot 进行锁定操作,锁定后内部内容无法选中;

在组件树可以解除操作。
## 组件编辑态
低代码引擎允许组件在编辑状态下表现得和渲染时不一样。Demo 中的布局组件就是用对应 API 完成布局的高级操作的。
它背后的实现有两种方法:
- 侵入型:组件编辑态下,会往组件内传入 `__designMode: 'design'`,可以在组件中进行相应处理;

- 双入口型:通过配置物料的 editUrls,加载专属于编辑态组件的物料。pro-layout 使用的是这种方式
```json
{
"package": "@alifd/pro-layout",
"version": "1.0.1-beta.6",
"library": "AlifdProLayout",
"urls": [
"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/dist/AlifdProLayout.js",
"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/dist/AlifdProLayout.css"
],
"editUrls": [
"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/build/lowcode/view.js",
"https://alifd.alicdn.com/npm/@alifd/pro-layout@1.0.1-beta.6/build/lowcode/view.css"
]
}
```
================================================
FILE: docs/docs/demoUsage/panels/code.md
================================================
---
title: 7. 源码面板详解
sidebar_position: 3
---
在源码面板中,您可以完成低代码中的代码部分编写。
## 面板功能拆解

### 代码编辑面板
代码编辑面板允许您书写 JavaScript 代码,并支持 JSX 语法。
由于依赖了 Babel,所以书写的 JSX 和 Chrome 80+ 以后的新语法也会被自动编译:
| 编译前 | 编译后 |
| --- | --- |
|  |  |
|  |  |
> 注:因为编译结果会被 `@babel/runtime` 干扰,目前面板不支持 `async await`或 `{ ...arr }` 形态的语法编译。如果您需要此类编译,您可以考虑在读取 schema 中的 `originCode` 之后自己手动通过 babel 编译。
#### 全局变量引用
在代码中,您可以通过 window 来引用全局变量。资产包中的 packages 都是通过 UMD 方式引入的对应内容,如果您引入了 Fusion Next(Demo 中默认引入),那么可以通过此方法直接唤起 Fusion Next 的内容,如弹窗提示:
```typescript
window.Next.Message.success('成功')
```

#### 局部变量引用
您可以在成员函数中访问到如下变量:
- `this.state`
- `this.setState`
- `this.context.appHelper.utils`
- `this.context.appHelper.constants`
- `this.context.appHelper.requestHandlerMap`
- `this.context.components`
#### 读、写与异常处理
- 读取:每次打开面板时,都会尝试读取 schema 中的 originCode 字段,如果没有,则从 schema 上的字段还原代码;
- 写入:在关闭代码编辑面板(主动点击叉或者点击非代码编辑区块的被动关闭都算)时,将自动写入到 schema 中;您也可以在编辑过程中点击“保存”按钮手动保存;
| 源码面板中 | Schema 中 |
| --- | --- |
| 本地数据初始值设置: |  |
| 生命周期方法: |  |
| 自定义函数: |  |
| 编译前全量代码: |  |
- 异常处理:如果代码解析失败,它将无法被正常保存到 schema 中,此时编辑器会弹层提示:

### 样式编辑面板
您可以在这里书写 CSS 内容。它对应 schema 中的 css 字段:
| 源码面板中 | Schema 中 |
| --- | --- |
|  |  |
## 对接代码
### 生命周期对接
如果您书写了视图相关的声明周期方法,那么对应的方法会在视图的特定周期被调用。支持的生命周期函数在《阿里巴巴中后台前端搭建协议规范》中被定义,包含:
```typescript
{
componentDidMount(): void;
constructor(props: Record, context: any);
render(): void;
componentDidUpdate(prevProps: Record, prevState: Record, snapshot: Record): void;
componentWillUnmount(): void;
componentDidCatch(error: Error, info: any): void;
}
```
### 设置器面板对接
书写完了函数 / state 后,您可以在右侧的设置器面板中配置对代码的部分。
通常书写代码是为了对接低代码配置中的“变量绑定”、“事件回调”、“条件判断”和“循环”部分的。
#### 变量绑定


```json
{
"componentName": "NextBlockCell",
"id": "node_ockzmje8tf5",
"props": {
"bodyPadding": {
"type": "JSExpression",
"value": "this.state.text",
"mock": ""
}
}
}
```
#### 事件回调


```json
{
"componentName": "Filter",
"id": "node_ockzmj0cl11w",
"props": {
"__events": {
"eventDataList": [
{
"type": "componentEvent",
"name": "onSearch",
"relatedEventName": "closeDialog"
}
]
},
"onSearch": {
"type": "JSFunction",
"value": "function(){this.onSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) }"
}
}
}
```
#### 条件判断


```json
{
"componentName": "Filter",
"id": "node_ockzmj0cl11w",
"condition": {
"type": "JSExpression",
"value": "this.state.text",
"mock": true
}
}
```
#### 循环


```json
{
"componentName": "Filter",
"id": "node_ockzmj0cl11w",
"loop": {
"type": "JSExpression",
"value": "this.state.text",
"mock": true
}
}
```
================================================
FILE: docs/docs/demoUsage/panels/component.md
================================================
---
title: 4. 组件面板详解
sidebar_position: 0
---
## 概述
组件面板顾名思义就是承载组件的面板,组件面板会获取并解析传入给低代码引擎的资产包数据 (数据结构[点此查看](https://lowcode-engine.cn/assets)),得到需要被展示的组件列表,并根据分类、排序规则对组件进行排列,同时也提供了搜索功能。

## 组件信息
组件面板承载的组件信息有:
- 组件标题;
- 组件截图;
- 组件低代码 schema 片段;
- 组件分组;
- 组件分类;
- 是否隐藏组件;
- 关键词:关键词用于搜索,会聚合 name、title、description、keywords 等字段作为搜索匹配的目标;
其中标题和截图是我们能够看到的,schema 片段则是拖拽到设计器时会自动插入页面 schema 中,面板会根据分组、分类来对组件进行排列;
这些组件信息均通过资产包数据获取,字段对应关系如下图所示:

## 组件分组、分类排序
组件面板会把相同分组的组件放在同一个 tab 下,相同分类的组件放在同一个 collapse 中,同时也支持对 tab 和 collapse 进行排序;
由于是整体性的排序,组件自身的信息无法决定此排序,因此在资产包数据根节点新增了 sort 字段用于指定分组和分类的排序,具体定义在[《低代码引擎资产包协议规范》](https://lowcode-engine.cn/assets)2.4 sort 章节;
| **根属性名称** | **类型** | **说明** | **变量支持** | **默认值** |
| --- | --- | --- | --- | --- |
| sort.groupList | String[] | 组件分组,用于组件面板 tab 展示 | - | ['精选组件', '原子组件'] |
| sort.categoryList | String[] | 组件面板中同一个 tab 下的不同区间用 category 区分,category 的排序依照 categoryList 顺序排列 | - | ['通用', '数据展示', '表格类', '表单类'] |
## 搜索
组件面板会提取组件的 name、title、description、keywords 等字段作为搜索匹配的目标,因此除了能够通过组件名称、描述进行搜索外,还可以指定一些关键词-keywords,keywords 是数组也可以是字符串类型。
================================================
FILE: docs/docs/demoUsage/panels/datasource.md
================================================
---
title: 8. 数据源面板详解
sidebar_position: 4
---
## 🪚 概述
数据源面板主要负责管理低代码中远程数据源内容,通过可视化编辑的方式操作低代码协议中的数据源 Schema,配合 [数据源引擎](/site/docs/guide/design/datasourceEngine) 即可实现低代码中数据源的生产和消费;

数据源面板
## ❓如何使用
> 面板内包含了数据源创建、删除、编辑、排序、导入导出、复制以及搜索等能力,内置支持了 `fecth` & `JSONP`两种常用远程请求类型;
### 三步创建一个数据源

三步创建数据源
### 参数详解
> TODO
## ☠️ 更多介绍
### 数据源顺序
> 数据源为何支持排序功能,主要原因是数据源的加载存在先后顺序;接下来我们从协议层以及实现层看数据源之间的顺序关系;
TODO
### 如何定制数据源
#### 定制数据源类型(设计态)
#### 定制数据源请求实现(运行态)
> 当出现以下两种情况的时,我们需要定制数据源请求实现,
> - 当你默认提供的 `handler`无法满足你的需求
> - 定制了数据源类型,比如 `GraphQL`,需要实现一个对应的 `handler`
接下来我们来看一个例子,如何实现一个 `handler`
```javascript
import { RuntimeOptionsConfig } from '@alilc/lowcode-datasource-types';
import request from 'universal-request';
import { RequestOptions, AsObject } from 'universal-request/lib/types';
export function createFetchHandler(config?: Record) {
return async function(options: RuntimeOptionsConfig) {
const requestConfig: RequestOptions = {
...options,
url: options.uri,
method: options.method as RequestOptions['method'],
data: options.params as AsObject,
headers: options.headers as AsObject,
...config,
};
const response = await request(requestConfig);
return response;
};
}
```
低代码 fetch-handler 默认实现
以上代码是低代码内置的 fetch-handler 默认实现,内部使用了 `universal-request`,假如你们内部使用的 `axios`,你完全重新实现一个;
```javascript
import axios from 'axios';
export function createAxiosFetchHandler(config?: Record) {
return async function(options: RuntimeOptionsConfig) {
const requestConfig: RequestOptions = {
...options,
url: options.uri,
method: options.method as RequestOptions['method'],
data: options.params,
headers: options.headers,
...config,
};
const response = await axios(requestConfig);
return response;
};
}
```
##### 注册到 render
完成一个 Handler 后你可以通过以下方式接入到 render 或者出码中使用
###### 渲染 Render
```tsx
import React, { memo } from 'react';
import ReactRenderer from '@alilc/lowcode-react-renderer';
const SamplePreview = memo(() => {
return (
);
});
```
###### 出码
> 目前自定义只能通过重新定义类型来完成,接下来我们会给出码添加 requestHandlersMap 映射能力;如有需求请联系 荣彬 (github-id:xingmolu)
### 设计态启用数据源引擎
> 默认情况下设计态没有开启数据源引擎,我们可以在设计器 init 的时候来传递`requstHandlersMap`来开启;具体代码如下:
```javascript
import { init, plugins } from '@alilc/lowcode-engine';
import { RequestHandlersMap } from '@alilc/lowcode-datasource-types';
const preference = new Map();
(async function main() {
await plugins.register(scenarioSwitcher);
await registerPlugins();
init(document.getElementById('lce-container')!, {
// designMode: 'live',
// locale: 'zh-CN',
enableCondition: true,
enableCanvasLock: true,
// 默认绑定变量
supportVariableGlobally: true,
// simulatorUrl 在当 engine-core.js 同一个父路径下时是不需要配置的!!!
// 这里因为用的是 alifd cdn,在不同 npm 包,engine-core.js 和 react-simulator-renderer.js 是不同路径
simulatorUrl: [
'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@latest/dist/css/react-simulator-renderer.css',
'https://alifd.alicdn.com/npm/@alilc/lowcode-react-simulator-renderer@latest/dist/js/react-simulator-renderer.js'
],
requestHandlersMap: {
fetch: createAxiosFetchHandler()
}
}, preference);
})();
```
## 🥡 附录
### 数据源协议
| **参数** | **说明** | **类型** | **支持变量** | **默认值** | **备注** |
| --- | --- | --- | --- | --- | --- |
| 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 对象描述](/site/docs/specs/lowcode-spec#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 对象描述](/site/docs/specs/lowcode-spec#2315-componentdatasourceitemoptions-对象描述) |
### 运行时实现层:数据源引擎设计
[数据源引擎设计](/site/docs/guide/design/datasourceEngine)
================================================
FILE: docs/docs/demoUsage/panels/settings.md
================================================
---
title: 6. 设置面板详解
sidebar_position: 2
---
# 设置器介绍
## 展示区域
设置器,又称为 Setter,主要展示在编辑器的右边区域,如下图:

其中包含 属性、样式、事件、高级
- 属性:展示该物料常规的属性
- 样式:展示该物料样式的属性
- 事件:如果该物料有声明事件,则会出现事件面板,用于绑定事件。
- 高级:两个逻辑相关的属性,**条件渲染**和**循环**
## 设置器
上述区域中是有多项设置器的,对于一个组件来说,每一项配置都对应一个设置器,比如我们的配置是一个文本,我们需要的是文本设置器,我们需要配置的是数字,我们需要的就是数字设置器。
下图中的标题和按钮类型配置就分别是文本设置器和下拉框设置器。

我们提供了常用的设置器作为内置设置器,也提供了定制能力帮助大家开发特定需求的设置器。
# 内置设置器
| **预置 Setter** | **用途** |
| --- | --- |
| StringSetter | 短文本型数据设置器,不可换行 |
| NumberSetter | 数值型数据设置器, |
| BoolSetter | 布尔型数据设置器, |
| SelectSetter | 枚举型数据设置器,采用下拉的形式展现 |
| VariableSetter | 变量型数据设置器, |
| RadioGroupSetter | 枚举型数据设置器,采用 tab 选择的形式展现 |
| TextAreaSetter | 长文本型数据设置器,可换行 |
| DateSetter | 日期型数据设置器 |
| TimePicker | 时间型数据设置器 |
| DateYearSetter | 日期型 - 年数据设置器 |
| DateMonthSetter | 日期型 - 月数据设置器 |
| DateRangeSetter | 日期型数据设置器,可选择时间区间 |
| EventsSetter | 事件绑定设置器 |
| ColorSetter | 颜色设置器 |
| JsonSetter | json 型数据设置器 |
| StyleSetter | 样式设置器 |
| ClassNameSetter | 样式名设置器 |
| FunctionSetter | 函数型数据设置器 |
| MixedSetter | 混合型数据设置器 |
| SlotSetter | 节点型数据设置器 |
| ArraySetter | 列表数组行数据设置器 |
| ObjectSetter | 对象数据设置器,一般内嵌在 ArraySetter 中 |
# 设置器定制
## 编写 AltStringSetter
我们编写一个简单的 Setter,这里我们编写的 Setter 是 AltStringSetter。代码如下:
```javascript
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 {
componentDidMount() {
const { onChange, value, defaultValue } = this.props;
if (value == undefined && defaultValue) {
onChange(defaultValue);
}
}
// 声明 Setter 的 title
static displayName = 'AltStringSetter';
render() {
const { onChange, value, placeholder } = this.props;
return (
onChange(val)}
>
);
}
}
```
### setter 和 setter/plugin 之间的联动
我们采用 emit 来进行相互之前的通信,首先我们在 A setter 中进行事件注册:
```javascript
import { event } from '@ali/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 '@ali/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 的名字在物料中使用了。
```javascript
import AltStringSetter from './AltStringSetter';
import { setters } from '@alilc/lowcode-engine';
setters.registerSetter({
AltStringSetter: {
component: AltStringSetter,
}
});
```
## 物料中使用
我们需要将目标组件的属性值类型值配置到物料资源配置文件中,例如 `packages/demo/public/assets.json`
其中核心配置如下:
```json
{
"props": {
"isExtends": true,
"override": [
{
"name": "type",
"setter": "AltStringSetter"
}
]
}
}
```
在物料中的完整配置如下:
```json
{
"componentName": "Message",
"title": "Message",
"docUrl": "",
"screenshot": "",
"npm": {
"package": "@alifd/next",
"version": "1.19.18",
"exportName": "Message",
"main": "src/index.js",
"destructuring": true,
"subName": ""
},
"props": [
{
"name": "title",
"propType": "string",
"description": "标题",
"defaultValue": "标题"
},
{
"name": "type",
"propType": {
"type": "oneOf",
"value": [
"success",
"warning",
"error",
"notice",
"help",
"loading"
]
},
"description": "反馈类型",
"defaultValue": "success"
}
],
"configure": {
"props": {
"isExtends": true,
"override": [
{
"name": "type",
"setter": "AltStringSetter"
}
]
}
}
}
```
###
# 小结
本章介绍了设置器是什么,我们有哪些内置的设置器。以及当不满足设置器诉求时,我们如何定制一个设置器。
================================================
FILE: docs/docs/faq/faq001.md
================================================
---
title: build-scripts 的使用文档
sidebar_position: 1
tags: [FAQ]
---
build-scripts 是一个开源项目,详见 [https://github.com/ice-lab/build-scripts](https://github.com/ice-lab/build-scripts)
================================================
FILE: docs/docs/faq/faq002.md
================================================
---
title: 渲染唯一标识(key)
sidebar_position: 2
tags: [FAQ]
---
渲染唯一标识(key)和 React 中组件的 key 属性的原理是一致的,都是为了在渲染场景或者组件切换的场景中唯一标识一个组件。
你可以在组件右侧配置面板的「高级」中看到此配置项,该配置项一般配合「是否渲染」和「循环」功能使用。

## 以下场景必需设置「渲染唯一标识」
#### 场景一:同类组件切换
以下场景中,当「爱好」选择「游戏」时显示「最喜欢的游戏」,选择「运动」时显示「最喜欢的运动」

配置方式如下:
1. 增加变量数据源:hobby
2. 「最喜欢的游戏」表单标识设置为 game,「是否渲染」绑定变量「state.hobby === '游戏'」

3. 「最喜欢的运动」表单标识设置为 sport,「是否渲染」绑定变量「state.hobby === '运动'」
4. 「爱好」设置 onChange 动作

5. 「提交」按钮绑定 onClick 动作

按以上配置(不配置渲染唯一标识),确实可以实现切换爱好时下方的文本框切换,但在提交数据时会发现,即使选择了「运动」,提交的时候 sport 字段是「最喜欢的游戏」的值。
原因:在进行文本框组件切换时,由于没有设置 key,底层会「复用」切换之前的组件
以上场景只需要给两个组件配置「渲染唯一标识」即可。
================================================
FILE: docs/docs/faq/faq003.md
================================================
---
title: 点击事件如何添加参数
sidebar_position: 3
tags: [FAQ]
---
背景:
- [Antd Table 下 button 点击事件怎么拿到行数据?](https://github.com/alibaba/lowcode-engine/issues/341)
## 方式 1

参考 fusion protable,将操作列直接耦合 button 组件,因为 col.render 函数能拿到 行数据 record,那么 pro-table 组件封装的时候,就可以在渲染操作列按钮的时候,将 col.render 参数透传给 button 组件
## 方式 2
slot + 扩展参数

将扩展参数写成:
```json
{
record: this.record,
index: this.index
}
```
那事件处理函数的第二个参数即可得到:
```json
onClick_new_new(...args){
console.log(args)
}
```
================================================
FILE: docs/docs/faq/faq004.md
================================================
---
title: 最小渲染单元配置
sidebar_position: 4
tags: [FAQ]
---
## 背景
在低代码引擎画布中,每一个节点的更新是**增量更新**机制。也就是通过 API 监听到组件的参数配置变化的时候,只更新该节点。
一些场景下,父组件需要在子组件的属性变化,获取新的子组件的属性值,也就是从父组件开始渲染。
例如:父组件需要强制修改 children props 值。示例代码如下:
```
React.Children.forEach(children, (child: React.ReactElement) => {
// 子元素的参数只有 behavior,且 behavior 为 'READONLY';
const newChild = React.cloneElement(child, {
behavior: 'READONLY'
});
})
```
**对于这种场景,需要配置其为“最小渲染单元”****。**即:
> **最小渲染单元下的组件渲染和更新都从单元的根节点开始渲染和更新。如果嵌套了多层最小渲染单元,渲染会从最外层的最小渲染单元开始渲染。**
### 组件能力配置 component
| **字段** | **用途** | **类型** |
| --- | --- | --- |
| isContainer(A) | 是否容器组件 | Boolean |
| **isMinimalRenderUnit** | **默认值:false**
**是否是最小渲染单元** | **Boolean** |
| ... | | |
#### 配置示例
##### 标准配置文件
configure.component.isMinimalRenderUnit
```json
{
"componentName": "Table",
"title": "表格",
"category": "数据展示",
"props": [],
"configure": {
"supports": {
},
"props": [],
"component": {
// 添加如下配置
"isMinimalRenderUnit": true
},
"combined": []
},
"snippets": [],
"npm": {}
}
```
## 更新机制说明
1. 没有任何组件被标识为**最小渲染单元**,则是每个组件都伴随自身属性变更而重新渲染;
2. 将根组件标识为**最小渲染单元**,则是整个页面重新渲染;
3. 组件树的分支节点被标识为**最小渲染单元**,则分支节点之下(包括自身)节点属性变更,触发分支节点整体的重新渲染;(若有多个**最小渲染单元**在同一条路径上,从最外层的**最小渲染单元**开始渲染)
================================================
FILE: docs/docs/faq/faq005.md
================================================
---
title: 如何通过 this.utils 使用第三方工具扩展
sidebar_position: 5
tags: [FAQ]
---
## 设计器
### 通过引擎 API 配置
[API-init](/site/docs/api/init)
### 通过资产包

就可以在引擎代码中访问到 moment

PS:需要在 packages 中有相关的资源配置,例如:

否则在画布中可能会访问不到对应的资源。
## 预览态
[参考资料](/site/docs/guide/expand/runtime/renderer#apphelper)
================================================
FILE: docs/docs/faq/faq006.md
================================================
---
title: 如何通过 API 手动调用数据源请求
sidebar_position: 6
tags: [FAQ]
---
参考:[DataSource API](/site/docs/demoUsage/appendix/api)
================================================
FILE: docs/docs/faq/faq007.md
================================================
---
title: 设置面板中的高级 tab 如何配置
sidebar_position: 7
tags: [FAQ]
---

默认这个 tab 下的内容为引擎内置,如需要定制,可以使用以下 API
[https://lowcode-engine.cn/site/docs/api/material#物料元数据管道函数](https://lowcode-engine.cn/site/docs/api/material#物料元数据管道函数)
================================================
FILE: docs/docs/faq/faq008.md
================================================
---
title: 某某 npm 包对应的源码在哪里?
sidebar_position: 8
tags: [FAQ]
---
详见 [NPM 包对应源码位置汇总](/site/docs/guide/appendix/npms)
================================================
FILE: docs/docs/faq/faq009.md
================================================
---
title: 物料出现 Component Not Found 相关报错
sidebar_position: 9
tags: [FAQ]
---
## 预览态,antd 资产包按顺序加载,但是没有按顺序执行
资产包按顺序加载,但是没有按顺序执行,导致部分 js 执行的时候,依赖的资源没有准备好,报错了。
传给 @alilc/lowcode-react-renderer 的 components 值为空。
**解决方案**
LowCodeEngine 升级到 1.0.8
> 相关 PR:[https://github.com/alibaba/lowcode-engine/pull/383](https://github.com/alibaba/lowcode-engine/pull/383)
## 编辑态,snippets 和注入组件不对应
1.在控制台中输入
```json
AliLowCodeEngine.material.componentsMap
```
查看物料配置是否正常。

如果正常继续。
LowCodeEngine 需要升级到 1.0.10
```json
AliLowCodeEngine.project.simulator.renderer.components
```
看看对应的物料是否存在,如果不存在,排查物料问题。
如果不正常,查看资产包配置,其中资产包中的 `components` 和 `material.componentsMap` 生成有关系。
例如,物料配置信息在 @alilc/lowcode-materials 包里面,即需要在 components 中加上下面的代码
```javascript
"components": [{
"exportName": "AlilcLowcodeMaterialsMeta",
"npm": {
"package": "@alilc/lowcode-materials"
},
"url": "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.7/build/lowcode/meta.js",
"urls": {
"default": "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.7/build/lowcode/meta.js",
"design": "https://alifd.alicdn.com/npm/@alilc/lowcode-materials@1.0.7/build/lowcode/meta.design.js"
}
}]
```
`material.componentsMap` 不存在相关的组件信息,原因有两个:
- 没有添加对应的物料到 components 字段中
- components 配置不正确,需要查看 url 是否正常加载,查看 exportName 是否配置正确,即 `window.${exportName}` 是否存在。
2.选中组件,在控制台中输入
```json
AliLowCodeEngine.project.currentDocument.selection.getNodes()[0].exportSchema('render')
```
查看 componentName 是否匹配。
3.调用 rerender 方法
```json
AliLowCodeEngine.project.simulator.rerender()
```
看一下问题是否恢复。
## 排查物料问题
找到对应组件的资产包,比如下图的资产包。
```json
{
"package": "@yingzhi8/lowcode-public-package",
"version": "0.1.2",
"library": "BizComps",
"urls": [
"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.js",
"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.css"
],
"editUrls": [
"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/view.js",
"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/view.css"
],
"advancedUrls": {
"default": [
"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.js",
"https://unpkg.com/@yingzhi8/lowcode-public-package@0.1.2/build/lowcode/render/default/view.css"
]
},
"advancedEditUrls": {}
}
```
### 查看 urls 是否加载
通过查看控制台,看加载的 urls
### library 配置是否正确
library 是可以在画布上访问到全局变量,确定 library 是否正确,在控制台输入:
```json
AliLowCodeEngine.project.simulator.contentWindow.${library}
```
================================================
FILE: docs/docs/faq/faq010.md
================================================
---
title: 插件面板如何调整位置
sidebar_position: 10
tags: [FAQ]
---
使用 index 配置来定义位置,内置的默认都是 0
```json
AliLowCodeEngine.skeleton.add({
area: 'leftArea',
type: 'PanelDock',
name: 'xxx',
content: () => 'xxx',
index: -1, // 使用 index 来定义位置,内置的默认都是 0
props: { icon: () => 'x' /* ReactElement 也可以 */ },
});
```
这里设置 index 为负数,可以将其调整到第一的位置。

================================================
FILE: docs/docs/faq/faq011.md
================================================
---
title: 如何获取物料当前处于编辑态还是渲染态
sidebar_position: 11
tags: [FAQ]
---
## 简单场景
可以利用 props.__designMode

设计态中,__designMode 值为 "design"
渲染态中,__designMode 没有设置值
## 复杂场景
在资产包里定义 editUrls

### editUrls
在 lowcode/xx/ 下新建一个 view.tsx

再执行
```json
npm run lowcode:build
```
之后,build/lowcode 目录下既有 view.js,可作为 editUrls 配置在资产包中。

================================================
FILE: docs/docs/faq/faq012.md
================================================
---
title: Procode 物料如何调用数据源方法
sidebar_position: 12
tags: [FAQ]
---
## 解决方案
给物料插入如下配置,可以默认给物料提供 reloadDataSource 的参数。
```json
{
title: {
label: {
type: 'i18n',
'en-US': 'reloadDataSource',
'zh-CN': 'reloadDataSource',
},
},
name: 'reloadDataSource',
setter: 'StringSetter',
initialValue: () => (
{
"type": "JSFunction",
"value": "function(){ return this.reloadDataSource; }"
}
),
},
```
在物料组件中,即可掉用如下代码来获取到相关方法。
```json
const reloadDataSource = props.getReloadDataSource()
```
## FAQ
### 希望该配置在配置面板中不展示
在配置中加上
```json
condition: () => false,
```
完整示例
```json
{
title: {
label: {
type: 'i18n',
'en-US': 'reloadDataSource',
'zh-CN': 'reloadDataSource',
},
},
name: 'reloadDataSource',
setter: 'StringSetter',
condition: () => false,
initialValue: () => (
{
"type": "JSFunction",
"value": "function(){ return this.reloadDataSource; }"
}
),
},
```
### 配置没有生效
查看组件中的 schema,对应的配置是否已经正确设置。

没有正确设置上可能的原因是
1.snippets 中没有默认值
需要按照如下的代码中,加上默认的参数配置
```json
const snippets: Snippet[] = [
{
title: 'Field',
screenshot: '',
schema: {
componentName: 'ProField',
props: {
type: 'textarea',
value: '我是测试',
getReloadDataSource: {
"type": "JSFunction",
"value": "function(){ return this.reloadDataSource; }"
}
},
},
},
];
```
### 如何全局生效
通过 [registerMetadataTransducer API](/site/docs/api/material#registermetadatatransducer) 来修改元数据信息,注意如果有 snippets 相关配置也需要修改相关的配置。
================================================
FILE: docs/docs/faq/faq013.md
================================================
---
title: Modal 类组件 hidden 属性被强制设置 true
sidebar_position: 13
tags: [FAQ]
---
## 注意
弹窗的正确弹出方式请参考:[如何通过按钮展示/隐藏弹窗](/site/docs/demoUsage/makeStuff/dialog)
## 问题原因
由于 hidden 属性,导致 Modal 组件在预览的时候不渲染,也就无法获取到实例。
## 处理方式
### 【推荐】升级到 Engine Verison 1.0.11 以上
### 新增 save propsReducer
通过新增 Save 态的 propsReducer,将 hidden props 去掉。可以参考下面的代码:
```typescript
import { project } from '@alilc/lowcode-engine';
import { IPublicEnumTransformStage } from '@alilc/lowcode-types';
export const deleteHiddenTransducer = (ctx: any) => {
return {
name: 'deleteHiddenTransducer',
async init() {
project.addPropsTransducer((props: any): any => {
delete props.hidden;
return props;
}, IPublicEnumTransformStage.Save);
},
};
}
deleteHiddenTransducer.pluginName = 'deleteHiddenTransducer';
```
### 导出 schema 使用 Save 态
```typescript
import { TransformStage } from '@alilc/lowcode-types';
const schema = project.exportSchema(TransformStage.Save)
```
================================================
FILE: docs/docs/faq/faq014.md
================================================
---
title: VERSION_PLACEHOLDER is not defined
sidebar_position: 14
tags: [FAQ]
---
# 问题原因
由于 lowcode-engine 目前只提供 cdn 的使用方式。如果是自己创建的项目,遇到这个报错了,主要是因为将 npm 包打包进去了。
# 解决方案
## engine-demo 项目
在项目的 externals 配置里加[一行配置](https://github.com/alibaba/lowcode-demo/blob/f8afad0df3190565caccc0a1dfd750dbf84c680f/build.json#L16)
## 其他项目
[相关文档](/site/docs/guide/create/useEditor#引入-umd-包资源)
### webpack
[https://webpack.docschina.org/configuration/externals/](https://webpack.docschina.org/configuration/externals/)
### 使用文档
待补充
================================================
FILE: docs/docs/faq/faq015.md
================================================
---
title: 已有组件如何快速接入引擎
sidebar_position: 15
tags: [FAQ]
---
你可以通过在线工具「Parts 造物」生产物料描述协议,然后使用到你的项目中去。
文档地址:[利用 Parts 造物快速使用 react 组件](/site/docs/guide/expand/editor/parts/partsIntro)
================================================
FILE: docs/docs/faq/faq016.md
================================================
---
title: Cannot read property 'Icon' of Undefined
sidebar_position: 16
tags: [FAQ]
---
@alifd/next 是 React 画布下必须的资源,不能省略。
需要在资产包中检查是否有下列代码:
```typescript
{
"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"
},
```
================================================
FILE: docs/docs/faq/faq017.md
================================================
---
title: vue 画布支持说明
sidebar_position: 17
tags: [FAQ]
---
#### 低代码引擎官方是否支持 Vue 画布
短期没有支持的计划
#### 社区研发的 Vue 画布
##### 肯耐珂萨团队实现的 Vue 画布
github:[https://github.com/KNXCloud/lowcode-engine-vue](https://github.com/KNXCloud/lowcode-engine-vue)
================================================
FILE: docs/docs/faq/faq018.md
================================================
---
title: 是否可以生成 Vue 页面代码?
sidebar_position: 18
tags: [FAQ]
---
低代码引擎在架构上是和具体语言无关的,通过一定的扩展和插件是可以生成 Vue 页面代码的。
如果只是用现有的基于 React 的 fusion 物料来搭建,只是在最终出码的时候生成 Vue 页面代码,那您需要准备一套和 fusion 兼容的 vue 物料,并定制个出码方案,将[下面的一些出码插件](https://github.com/alibaba/lowcode-engine/blob/main/modules/code-generator/src/solutions/icejs.ts)替换成生成 Vue 框架的即可:

详细定制方案可以参考下[《自定义出码》](/site/docs/guide/expand/runtime/codeGeneration#5自定义出码)。
如果您希望在搭建的时候也使用 Vue 的物料,则还需要扩展定制入料、画布和渲染器等模块,详细方案请参考下[《扩展低代码编辑器》](/site/docs/guide/expand/editor/summary)
================================================
FILE: docs/docs/faq/faq019.md
================================================
---
title: windows 下运行出现报错
sidebar_position: 19
tags: [FAQ]
---
由于阿里内部研发人员没有 windows 开发的诉求,windows 环境下相关的技术兼容短期内暂时没有支持计划。
辛苦使用 [WSL](https://docs.microsoft.com/zh-cn/windows/wsl/install) 在 windows 下进行低代码引擎相关的开发。
如果可以的话,欢迎大佬们提 PR 对 windows 开发环境进行兼容方面的支持。
================================================
FILE: docs/docs/faq/faq020.md
================================================
---
title: Can't import the named export from non ECMAScript module
sidebar_position: 20
tags: [FAQ]
---
如果您是自己配置的引擎打包,那么可能会遇到这个问题。

问题的根源是 code-editor 插件运行时直接依赖了 babel 来完成 jsx 编译,babel 从 7.17.0 开始依赖了使用 ESM 编写的 @ampproject/remapping@2.1.0。如果打包工具无法正确处理 ESM,则可能报错。
解决方案 1:锁定 babel 版本
如果您使用了 yarn,那么可以在 package.json 中:
```typescript
"resolutions": {
"@babel/core": "~7.16.7",
"@babel/parser": "~7.16.7",
"@babel/preset-env": "~7.16.7",
"@babel/preset-react": "~7.16.7",
"@babel/standalone": "~7.16.7",
"@babel/traverse": "~7.16.7",
"@babel/types": "~7.16.7"
}
```
解决方案 2:编译层面配置。本例使用 build-script 配置,您可以用类似方法来配置您的 webpack:
```typescript
module.exports = ({ onGetWebpackConfig }) => {
// see: https://github.com/ice-lab/build-scripts#%E6%8F%92%E4%BB%B6%E5%BC%80%E5%8F%91
onGetWebpackConfig((config) => {
config.module // fixes https://github.com/graphql/graphql-js/issues/1272
.rule('mjs$')
.test(/\.mjs$/)
.include
.add(/node_modules/)
.end()
.type('javascript/auto');
return config;
});
};
```
================================================
FILE: docs/docs/faq/faq021.md
================================================
---
title: 提交 PR 时,明明签署过 CLA,仍被提示需要签署
sidebar_position: 21
tags: [FAQ]
---
## 问题原因
原因是:git commit 时,本地 git config 配置的 email 与 github 账号的 email 不一致,导致未被识别出来,检查方式
```bash
git config user.email
```
## 解决办法
如何配置,可参考 [is-it-possible-to-have-different-git-configuration-for-different-projects](https://stackoverflow.com/questions/8801729/is-it-possible-to-have-different-git-configuration-for-different-projects)
配置好正确的 email 之后,已提交的代码需要以新的配置重新提交才可生效。
================================================
FILE: docs/docs/faq/faq022.md
================================================
---
title: 节点无法拖拽到 Page 下
sidebar_position: 22
tags: [FAQ]
---
查看 Page 节点的 childWhitelist 配置,如果 Page 配置了 childWhitelist,且当前节点不在白名单下,是无法拖拽的。
```typescript
AliLowCodeEngine.material.getComponentMeta('Page').getMetadata().configure.component.nestingRule.childWhitelist
```
比如在 [demo](https://lowcode-engine.cn/demo/demo-general/index.html) 中 Page 组件的 childWhitelist 为:['NextPage', 'ProDialog', 'Dialog', 'Drawer'],则只有这些组件可以拖拽到 Page 的 children 下,其他组件均不可以。
说明:1.0.15 之前 Page 组件的 childWhitelist 限制是失效的,在 1.0.16 版本进行了 bug 修复。
### 解决办法
**方法 1:直接修改 Page 组件的 childWhitelist,比如删除**。
**方法 2:通过 **[**material.registerMetadataTransducer**](/site/docs/api/material#registermetadatatransducer)** 修改 Page 组件的 childWhitelist(适用于 Page 组件是其他人维护的)**
================================================
FILE: docs/docs/faq/faq023.md
================================================
---
title: Slot组件渲染报错问题
sidebar_position: 23
tags: [FAQ]
---
## 问题描述
在低代码引擎的页面渲染过程中,可能会遇到一个关于Slot组件的报错,提示“Slot找不到”。实际上,在渲染态时不应使用Slot组件。
## 问题原因
低代码引擎渲染分为两个状态:设计态和渲染态。
- **设计态**:为了帮助插槽进行可视化设计,引入了Slot组件。
- **渲染态**:在此状态下,不需要使用Slot组件。
这个问题通常是因为在渲染态错误地使用了设计态的schema。
## 解决方案
1. **区分设计态和渲染态**:通过`project.exportSchema(TransformStage.Save)`的参数来区分。
- `TransformStage.Save`代表渲染态的schema,其中不包含Slot组件。
- 【默认值】`TransformStage.Render`代表设计态的schema,其中包含Slot组件。
2. **使用正确的API和参数**:确保在渲染态使用正确的schema,避免引用设计态的Slot组件。
3. **处理脏数据问题**:如果问题是由脏数据导致,清除数据并重新拖拽组件以恢复正常。
## 注意事项
- 确保在代码和配置中正确区分设计态和渲染态。
- 如果遇到持续的问题,检查是否有脏数据或配置错误,并进行相应的清理和调整。
## 相关链接
- Issue链接:[Issue #1798](https://github.com/alibaba/lowcode-engine/issues/1798)
---
================================================
FILE: docs/docs/faq/faq024.md
================================================
---
title: workspace 模式常见问题
sidebar_position: 23
tags: [FAQ]
---
#### 如何判断是否开启了IDE模式?
- **通过官方API判断**:您可以通过访问 [workspace.isActive](/site/docs/api/workspace#isactive) 来判断当前是否处于IDE模式。这是阿里低代码引擎提供的一个官方API,专门用于确认是否处于集成开发环境。
#### 如何使用插件的ctx来做判断在哪个模式下?
- **插件是否为应用级别**:可以通过 **ctx.isPluginRegisteredInWorkspace** 方法来判断一个插件是否是应用级别的插件。这有助于理解插件在阿里低代码引擎中的作用域和潜在的使用场景。
- **插件的注册级别**:您可以使用 **ctx.registerLevel** 属性来判断插件处于哪个级别。插件级别的值包括:
- **Default**:默认级别。非 IDE 模式下的值
- **Workspace**:应用级别。
- **Resource**:资源级别。
- **EditorView**:编辑视图级别。 这些级别代表了插件可能的作用域和使用场景,有助于在开发和管理低代码应用时对插件进行更精确的控制和配置。
#### 如何在IDE模式下设置资源列表?
- **设置资源列表API**:在IDE模式下,可以通过访问 [workspace.setResourceList](/site/docs/api/workspace#setresourcelist) 来设置或更新IDE中的资源列表。这确保您在编辑器窗口中打开的资源是最新且可访问的。
#### 如何打开视图窗口?
- **使用推荐的方法**:使用 `openEditorWindow(resource: Resource, sleep?: boolean): Promise;` 来打开视图窗口。这里的 **resource** 参数指的是您要打开的特定资源,可通过 [workspace.resourceList](/site/docs/api/workspace#resourcelist) 获取。
- **不推荐使用的过时方法**:有一个过时的方法 `openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise;` 也用于打开视图窗口。虽然仍然可用,但官方不推荐使用此方法,并计划在后续版本中废弃,因为它在维护和可扩展性方面存在限制。
#### 如何在全局插件中获取视图的上下文?
- 在阿里低代码引擎的全局插件中获取视图的上下文,可以通过使用 **ProvideViewPluginContext** 函数实现。这个函数来自 **@alilc/lowcode-utils** 库,它使得您的 React 组件能够接收 **pluginContext** 作为 props,进而访问和操作当前视图的状态和属性。
**步骤**
**引入依赖**:首先,确保您的插件文件中已经引入了 **ProvideViewPluginContext** 以及其他必要的依赖。
```
import { ProvideViewPluginContext } from '@alilc/lowcode-utils';
```
**定义 React 组件**:创建一个 React 组件,它将使用来自 **ProvideViewPluginContext** 的 **pluginContext**。
```typescript
const MyComponent = (props) => {
const { pluginContext } = props;
// 组件逻辑
return /* 组件内容 */
;
};
```
**定义全局插件**:定义一个函数,这个函数会在插件被注册时调用。这个函数通常接受一个上下文对象 **ctx**,它提供了对引擎功能的访问。
```javascript
const globalPlugin = (ctx) => {
const { skeleton } = ctx;
skeleton.add({
type: 'PanelDock',
name: 'datapool',
content: ProvideViewPluginContext((props) => {
// 组件内容
return (
)
}),
// 其他配置
contentProps: {
// 需要提供 pluginContext 作为参数
pluginContext: ctx,
}
});
};
```
通过这些步骤,您的全局插件中的 React 组件就能够获取并使用视图的上下文了。这为您在插件中实现更复杂的功能和交互提供了基础。
**注意事项**
- **组件重渲染**:正常情况下,**pluginsContext** 是视图的上下文。当视图切换时,组件会重新渲染。如果需要在组件中处理视图切换导致的重新渲染,可以利用 React 的 **key** 属性。
**示例代码**
```typescript
ProvideViewPluginContext(props => {
return (
Boolean | 是否展示 |
| config.items[].getValue | (target, value) => value | 数据获取的 hook,可修改获取数据 |
| config.items[].setValue | (target, value) => value | 数据获取的 hook,可修改设置数据 |
================================================
FILE: docs/docs/guide/appendix/setterDetails/behavior.md
================================================
---
title: BehaviorSetter
---
详见 [npm 包说明](https://g.alicdn.com/code/npm/@ali/lowcode-setter-behavior/0.1.1/build/index.html)
================================================
FILE: docs/docs/guide/appendix/setterDetails/bool.md
================================================
---
title: BoolSetter
---
## 简介
开关选择器
## 展示

## setter 配置
| 属性名 | 说明 |
| --- | --- |
| disabled | 是否可选 |
| defaultValue | 默认值 |
## 返回类型
Boolean
================================================
FILE: docs/docs/guide/appendix/setterDetails/color.md
================================================
---
title: ColorSetter
---
用来选择颜色。
## 展示
## setter 配置
| 属性名 | 说明 |
| --- | --- |
| defaultValue | 默认值 |
## 返回类型
String
会返回 options 中的 value 值
================================================
FILE: docs/docs/guide/appendix/setterDetails/event.md
================================================
---
title: EventSetter
---
## 简介
可以将事件绑定在物料上
## 展示
## 组件自带事件列表
在物料协议的 configure.supports.events 中声明
```json
{
"configure ": {
"supports": {
"style": true,
"events": [{
"name": "onChange"
}, {
"name": "onExpand"
}, {
"name": "onVisibleChange"
}]
}
}
}
```
## 事件绑定

可以选择已有的事件 (schema 中的**methods**节点) 进行绑定,也可以选择新建事件,选择新建事件默认会增加_new 的事件后缀命名,点确定以后会跳转到对应代码插件对应区块。
## 参数设置
如果需要额外传参,需要将扩展参数设置打开,在代码面板中,编辑参数内容。
注意:
- 额外参数必须被包装成一个对象,如参数模板中所示
- 可以使用动态变量例如 (this.items,this.state.xxx)
```javascript
{
testKey: this.state.text,
}
```
- 该参数是额外参数,会加在原有参数后面,例如在 onClick 中加入扩展传参,最终函数消费的时候应该如下所示
```javascript
// e 为 onClick 原有函数传参,extParams 为自定义传参
onClick(e, extParams) {
this.setState({
isShowDialog: extParams.isShowDialog,
});
}
```
## 事件新建函数模板
有时候我们创建的函数会有用到一些通用的函数模板,我们可以在物料协议的 events.template 中创建一个模板,如下
```json
{
"configure ": {
"supports": {
"style": true,
"events": [{
"name": "onChange",
"template": "templeteTest(e,${extParams}){this.setState({isShowDialog: false})}"
}, {
"name": "onExpand"
}, {
"name": "onVisibleChange"
}]
}
}
}
```
其中 ${extParams} 为扩展参数占位符,如果用户没有声明扩展参数,会移除对应的参数声明,定义模板后,每次创建完函数会自动生成模板函数,如下图

================================================
FILE: docs/docs/guide/appendix/setterDetails/function.md
================================================
---
title: FunctionSetter
---
## 简介
可以将function绑定在物料上
## 设置器返回
设置器返回一个Function对象,调用function()运行Function对象得到运行结果。
如下是一个典型的使用案例:
```javascript
export type TestProps = React.ComponentProps & {
testFunction?: Function | undefined;
};
const getTestData = () => {
if(this.props.testFunction === undefined){
return undefined;
}else{
return this.props.testFunction() // 返回testFunction()方法的运行结果;
}
}
```
## 参数设置
如果需要额外传参,需要将扩展参数设置打开,在代码面板中,编辑参数内容。
注意:
- 额外参数必须被包装成一个对象,如参数模板中所示
- 可以使用动态变量例如 (this.items,this.state.xxx)
```javascript
{
testKey: this.state.text,
}
```
- 该参数是额外参数,会加在原有参数后面,例如在 onClick 中加入扩展传参,最终函数消费的时候应该如下所示
```javascript
// e 为 onClick 原有函数传参,extParams 为自定义传参
onClick(e, extParams) {
this.setState({
isShowDialog: extParams.isShowDialog,
});
}
```
## 事件新建函数模板
有时候我们创建的函数会有用到一些通用的函数模板,我们可以在物料协议的 meta.ts 中创建一个模板,如下
```TypeScript
{
name: 'onChange',
title: {
label: 'onChange',
tip: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
},
propType: 'func',
setter: [
{
componentName: 'FunctionSetter',
props: {
template: 'onTableChange(value,${extParams}){\n\n}',
},
},
],
}
```
其中 ${extParams} 为扩展参数占位符,如果用户没有声明扩展参数,会移除对应的参数声明。
================================================
FILE: docs/docs/guide/appendix/setterDetails/icon.md
================================================
---
title: IconSetter
---
## 简介
用来选择图标
## 展示
## setter 配置
| **属性名** | **类型** | **说明** |
| --- | --- | --- |
| type | String | 选择器返回类型 **可选值**: "string" \| "node" |
| defaultValue | String | ReactNode | 默认值 |
| hasClear | Boolean | 选择器是否显示清除按钮 |
| icons | Array | 自定义 icon 集合;默认值详见[图标可选值](#图标可选值) |
| placeholder | String | 没有值的时候的占位符 |
## 返回类型
String | ReactNode
## 图标可选值
```javascript
[
'smile',
'cry',
'success',
'warning',
'prompt',
'error',
'help',
'clock',
'success-filling',
'delete-filling',
'favorites-filling',
'add',
'minus',
'arrow-up',
'arrow-down',
'arrow-left',
'arrow-right',
'arrow-double-left',
'arrow-double-right',
'switch',
'sorting',
'descending',
'ascending',
'select',
'semi-select',
'loading',
'search',
'close',
'ellipsis',
'picture',
'calendar',
'ashbin',
'upload',
'download',
'set',
'edit',
'refresh',
'filter',
'attachment',
'account',
'email',
'atm',
'copy',
'exit',
'eye',
'eye-close',
'toggle-left',
'toggle-right',
'lock',
'unlock',
'chart-pie',
'chart-bar',
'form',
'detail',
'list',
'dashboard',
]
```
================================================
FILE: docs/docs/guide/appendix/setterDetails/mixed.md
================================================
---
title: MixedSetter
---
## 简介
可以让属性同时支持多个 setter
## 展示
## 配置
| **属性名** | **类型** | **说明** |
| --- | --- | --- |
| setters | Array | SetterName |
================================================
FILE: docs/docs/guide/appendix/setterDetails/number.md
================================================
---
title: NumberSetter
---
## 简介
用于输入数字。
## 展示
## setter 配置
| 属性名 | 说明 |
| --- | --- |
| min, max | 指定最大最小值 |
| defaultValue | 默认值 |
| step | 指定步长 number |
| units | 指定单位 string |
| precision | 设置小数位数 number |
## 返回类型
Number
会返回 value 值
================================================
FILE: docs/docs/guide/appendix/setterDetails/radioGroup.md
================================================
---
title: RadioGroupSetter
---
## 简介
用于直观的展示选择并选择。
## 展示
## setter 配置
| 属性名 | 说明 |
| --- | --- |
| defaultValue | 默认值 |
| options | 传入的数据源,**参数格式**: [{img: 'url', value: 'text', label/title: 'text'}, ...] \| [ 'text', 'text', ...] |
## 返回类型
String | Number | Boolean
会返回 options 中的 value 值
================================================
FILE: docs/docs/guide/appendix/setterDetails/select.md
================================================
---
title: SelectSetter
---
## 简介
用来选择组件。在限定的可选性内进行选择,核心能力是选择
## 展示
## setter 配置
| 属性名 | 说明 |
| --- | --- |
| mode | 选择器模式 可选值: 'single', 'multiple', 'tag' |
| defaultValue | 默认值 |
| options | 传入的数据源,**参数格式**: [ {label/title: '文字', value: 'text'}, ...] |
## 返回类型
String | Number | Boolean
会返回 options 中的 value 值
================================================
FILE: docs/docs/guide/appendix/setterDetails/slot.md
================================================
---
title: SlotSetter
---
## 简介
通过一个开启一个 slot(插槽),可以在物料特定的一个位置渲染一个或者多个节点。slot 比较适合物料的局部自定义渲染。
## 展示
## setter 配置
| 属性名 | 类型 | 说明 |
| --- | --- | --- |
| initialValue | Object | 默认值 { "type": "JSSlot", "params": [ "module" ], "value": [] } params:接收函数的入参,可以直接在slot节点中消费,通过this.module (这里module是示例值,可根据实际函数入参更改) value:可以定义一个节点,每次打开插槽的时候默认填充一个节点 |
| hideParams | boolean | 是否隐藏入参,注意该值只能隐藏入参的输入框,适合单行展示,实际渲染的时候,还是会传入 params 的参数,和 params:[]不同 |
| checkedText | string | switch 选中文案,默认显示"启用" |
| unCheckedText | string | switch 取消文案,默认显示"关闭" |
## 配置示例
### 配置
```typescript
{
name: 'propName',
title: 'propTitle',
setter: {
componentName: 'SlotSetter',
isRequired: true,
title: '组件坑位',
initialValue: {
type: 'JSSlot',
value: [],
},
}
}
```
### 组件
```typescript
function A(props) {
return props.propName;
}
```
## 带参数的插槽示例
### 配置
```typescript
{
name: 'propName',
title: 'propTitle',
setter: {
componentName: 'SlotSetter',
isRequired: true,
title: '组件坑位',
initialValue: {
type: 'JSSlot',
params: [ 'module'],
value: [],
},
}
}
```
### 组件
组件需要传参数进行渲染,和普通示例的使用不一样。
```typescript
function A(props) {
const module = [];
return props.propName(module);
}
```
### param 使用示例
1.开启插槽

2.拖拽组件到插槽中

3.在插槽内组件中使用变量绑定,绑定 this.xxx
xxx 入参的配置

================================================
FILE: docs/docs/guide/appendix/setterDetails/string.md
================================================
---
title: StringSetter
---
## 简介
用来展示和修改字符串类型的属性值,不可换行
## 展示
## setter 配置
| 属性名 | 说明 |
| --- | --- |
| placeholder | 输入提示 |
## 返回类型
String
================================================
FILE: docs/docs/guide/appendix/setterDetails/style.md
================================================
---
title: StyleSetter
---
## 简介
通过开启 StyleSetter,我们可以将样式配置面板来配置样式属性。
## 展示
## setter 配置
| 属性名 | 类型 | 说明 |
| --- | --- | --- |
| unit | String | 默认值 px
|
| placeholderScale | Number | 默认计算尺寸缩放 默认值为 1
在没有设定数值的时候,系统会通过 window.getComputedStyle 来计算展示的数值。在某些场景下,例如手机场景,在编辑器展示的是 375 的实际宽度,但是实际设计尺寸是 750 的宽度,这个时候需要对这个计算尺寸设成 2 |
| showModuleList | String[] | 默认值 ['background', 'border', 'font', 'layout', 'position'] 分别对应背景、边框、文字、布局、位置五个区块,可以针对不同的场景按需进行展示。 例如文字的组件,我不需要修改边框的样式,就可以把边框模块隐藏掉 |
| isShowCssCode | Boolean | 默认值: true, 是否展示css源码编辑 |
| layoutPropsConfig | Object | 布局样式设置 |
| layoutPropsConfig.showDisPlayList | String[] | 默认值 ['inline', 'flex', 'block', 'inline-block', 'none']
可按需展示 |
| layoutPropsConfig.isShowPadding | String | 默认值 true
是否展示内边距(四个边) ||
| layoutPropsConfig.isShowMargin | Boolean | 默认值 true
是否展示外边距(四个边) ||
| layoutPropsConfig.isShowWidthHeight | Boolean | 默认值 true
是否展示宽高 |
| fontPropsConfig | Object | 文字样式设置 |
| fontPropsConfig.fontFamilyList | Array | [ { value: 'Helvetica', label: 'Helvetica' }, { value: 'Arial', label: 'Arial' },] 可以定制文字字体选项 |
| positionPropsConfig | Object | 位置样式设置 |
| positionPropsConfig.isShowFloat | Boolean | 默认 true 是否展示浮动 |
| positionPropsConfig.isShowClear | Boolean | 默认 true 是否展示清除浮动 |
================================================
FILE: docs/docs/guide/appendix/setterDetails/textArea.md
================================================
---
title: TextAreaSetter
---
## 简介
表单输入组件。
## 展示
## setter 配置
| **属性名** | **类型** | **说明** |
| --- | --- | --- |
| placeholder | String | 输入提示 |
## 返回类型
String
================================================
FILE: docs/docs/guide/appendix/setterDetails/variable.md
================================================
---
title: VariableSetter
---
## 简介
用来给属性值设定变量
## 展示
## 变量列表
包含所有的在协议中的**state**(state 属性) 节点数据和**methods**(自定义处理函数) 节点数据
================================================
FILE: docs/docs/guide/appendix/setters.md
================================================
---
title: 预置设置器列表
sidebar_position: 4
---
| 预置 Setter | 返回类型 | 用途 | 截图 |
| --- | --- | --- | --- |
| [ArraySetter](./setterDetails/array) | T[] | 列表数组行数据设置器 |  |
| [BoolSetter](./setterDetails/behavior) | boolean | 布尔型数据设置器, |  |
| ClassNameSetter | string | 样式名设置器 |  |
| [ColorSetter](./setterDetails/color) | string | 颜色设置器 |  |
| DateMonthSetter | | 日期型 - 月数据设置器 | |
| DateRangeSetter | | 日期型数据设置器,可选择时间区间 | |
| DateSetter | | 日期型数据设置器 | |
| DateYearSetter || 日期型 - 年数据设置器 | |
| [EventSetter](./setterDetails/event) | function | 事件绑定设置器 |  |
| [IconSetter](./setterDetails/icon) | string | 图标设置器 |  |
| [FunctionSetter](./setterDetails/function) | function | 函数型数据设置器 |  |
| JsonSetter | object | json 型数据设置器 |  |
| [MixedSetter](./setterDetails/mixed) | any | 混合型数据设置器 |  |
| [NumberSetter](./setterDetails/number) | number | 数值型数据设置器 |  |
| ObjectSetter | Record | 对象数据设置器,一般内嵌在 ArraySetter 中 ||
| [RadioGroupSetter](./setterDetails/radioGroup)| string | number | boolean | 枚举型数据设置器,采用 tab 选择的形式展现 ||  |
| [SelectSetter](./setterDetails/select) | string | number | boolean | 枚举型数据设置器,采用下拉的形式展现 |  |
| [SlotSetter](./setterDetails/slot) | Element | Element[] | 节点型数据设置器 |  |
| [StringSetter](./setterDetails/string) | string | 短文本型数据设置器,不可换行 |  |
| StyleSetter || 样式设置器 |  |
| [TextAreaSetter](./setterDetails/textArea) | string | 长文本型数据设置器,可换行 |  |
| TimePicker | | 时间型数据设置器 ||
| [VariableSetter](./setterDetails/variable) | any | 变量型数据设置器, |  |
================================================
FILE: docs/docs/guide/create/_category_.json
================================================
{
"label": "创建低代码编辑器",
"position": 1,
"collapsed": false,
"collapsible": true
}
================================================
FILE: docs/docs/guide/create/useEditor.md
================================================
---
title: 接入编辑器
sidebar_position: 0
---
您有两种方式初始化低代码编辑器:
1. clone 低代码项目的官方 demo,直接启动项目。适合普通人。
2. 手工引入低代码 UMD 包,手工配置、打包和启动。适合 Webpack 配置工程师。
## 方法 1:通过官方命令行工具创建编辑器
1. 确保本地安装了 Node.js 和 npm,如果没有,[您可以通过 nvm 进行快捷的安装](https://github.com/nvm-sh/nvm)
2. 确保为 npm [设置了可以访问的 npm 源,保证安装过程无网络问题](https://npmmirror.com/)
3. 安装官方命令行工具
```bash
npm install -g @alilc/create-element@latest
```
4. 通过命令行工具创建
```bash
npm init @alilc/element editor-project-name
```
这时会看到一个选项列表
选择`编辑器`,并填写对应的问题,即可完成创建。
> 注 @alilc/create-element 版本需 >= 1.0.4,若看不到`编辑器`选项,请重新执行步骤 3
5. 进入创建后的目录
```bash
cd editor-project-name
```
6. 安装依赖
```bash
npm install
```
7. 安装依赖成功后,启动项目 (注意观察上一步的输出,如有 error 等失败信息,请先进行排查)
```bash
npm start
```
执行后如果看到这个界面,说明项目启动成功。您可以继续看后续章节了。本章节后续内容均为高级配置方式。

## 方法 2: 使用 UMD 包方式配置
如果您不是从零开始的项目,您可能需要手工引入低代码引擎。
### 引入 UMD 包资源
我们需要在启动前,正确在项目中通过 UMD 包方式直接依赖如下内容:
> 亦可使用异步加载工具,如果您按照正确的顺序进行加载
```html
```
> 注:如果 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)章节。
================================================
FILE: docs/docs/guide/create/useRenderer.md
================================================
---
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)
## 低代码的生产和消费流程总览
经过“接入编辑器” - “接入运行时”这两节的介绍,我们已经可以了解到低代码所构建的生产和消费流程了,梳理如下图:

如上述流程所示,您一般需要一个后端项目来保存页面数据信息,如果资产包信息是动态的,也需要保存资产包信息。
================================================
FILE: docs/docs/guide/design/_category_.json
================================================
{
"label": "引擎设计原理",
"position": 3,
"collapsed": false,
"collapsible": true
}
================================================
FILE: docs/docs/guide/design/datasourceEngine.md
================================================
---
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;
}
```
================================================
FILE: docs/docs/guide/design/editor.md
================================================
---
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 做一个动态的监听。
#### 插件机制
我们希望保持引擎内核足够小,但拥有足够强的扩展能力,所有扩展功能都通过插件机制来承载。
================================================
FILE: docs/docs/guide/design/generator.md
================================================
---
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 这个代码格式化工具。
================================================
FILE: docs/docs/guide/design/materialParser.md
================================================
---
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 库。
### 整体大图
把上述的静态解析和动态解析流程结合起来,可以得到以下大图。

================================================
FILE: docs/docs/guide/design/renderer.md
================================================
---
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 来做关系图编排。你可以定制一个流式布局的画布,也可以定制一个自由布局的画布。
================================================
FILE: docs/docs/guide/design/setter.md
================================================
---
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....
}
```
================================================
FILE: docs/docs/guide/design/specs.md
================================================
---
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,其他平台可以参考低代码引擎进行实现,满足官方协议,便也可以消费相关的物料生态和其他生态。
================================================
FILE: docs/docs/guide/design/summary.md
================================================
---
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)} />;
}
}
```
大多数组件所使用的设置器都是一致或相似的。如同建设低代码基础组件库一样,设置器生态是一组基础的设置器,供大多数组件配置场景使用。
同时提供了设置器的定制功能。
### 插件生态
低代码引擎本身只包含了最小的内核,而我们所能看到的设计器上的按钮、面板等都是插件提供的。插件是组成设计器的必要部分。
因此我们提供了一套官方的插件生态,提供最基础的设计器功能。帮助用户通过使用插件,快速完成自己的设计器。
================================================
FILE: docs/docs/guide/expand/_category_.json
================================================
{
"label": "扩展低代码编辑器",
"position": 2,
"collapsed": false,
"collapsible": true
}
================================================
FILE: docs/docs/guide/expand/editor/_category_.json
================================================
{
"label": "扩展编辑态",
"position": 1,
"collapsed": false,
"collapsible": true
}
================================================
FILE: docs/docs/guide/expand/editor/cli.md
================================================
---
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; // 物料设计态入口,仅组件包含,尚未实现
}
}
```
================================================
FILE: docs/docs/guide/expand/editor/graph.md
================================================
---
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"即可进入物料调试

================================================
FILE: docs/docs/guide/expand/editor/material.md
================================================
---
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));
```
================================================
FILE: docs/docs/guide/expand/editor/metaSpec.md
================================================
---
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,
};
}
),
),
},
};
}
}
```
================================================
FILE: docs/docs/guide/expand/editor/parts/_category_.json
================================================
{
"label": "Parts 造物",
"position": 1
}
================================================
FILE: docs/docs/guide/expand/editor/parts/partsIntro.md
================================================
---
title: 介绍
sidebar_position: 1
---
## 介绍

「Parts·造物」是基于开源低代码引擎打造的次时代物料研发和集成工具,一方面作为低代码引擎搭建低代码平台的一个样板展示开源生态下的各个组件如何集合在一起形成生产力,另一方面也可以生产低代码平台所需的物料。
目前「Parts·造物」主要提供两大产品功能:
1. React 组件导入低代码引擎:通过在线可视化的「物料描述」配置,任意工具开发的 React 组件都可以快速完成对低代码引擎的适配,导入到低代码引擎项目中进行使用。不必额外开发新的组件。
2. 低代码生产组件:通过低代码的形式生产组件,极低上手门槛,提供丰富的原子组件用于组合,完善的调试预览和组件生命周期控制。生产的组件既可以在低代码引擎项目中使用,也可以出码后在普通源码项目中使用。
## 联系我们
================================================
FILE: docs/docs/guide/expand/editor/parts/partsassets.md
================================================
---
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: '',
});
}
};
}
```
## 联系我们
================================================
FILE: docs/docs/guide/expand/editor/parts/partslcc.md
================================================
---
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 源中。

注意:目前导出功能暂不支持 低代码组件嵌套。
## 联系我们
================================================
FILE: docs/docs/guide/expand/editor/parts/prototype.md
================================================
---
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#使用资产包)
## 联系我们
================================================
FILE: docs/docs/guide/expand/editor/pluginContextMenu.md
================================================
---
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/)
================================================
FILE: docs/docs/guide/expand/editor/pluginWidget.md
================================================
---
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/)
================================================
FILE: docs/docs/guide/expand/editor/setter.md
================================================
---
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"
}
]
}
}
```
================================================
FILE: docs/docs/guide/expand/editor/summary.md
================================================
---
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)
================================================
FILE: docs/docs/guide/expand/editor/theme.md
================================================
---
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 组件,这样可以无缝地集成到您的应用设计中。
================================================
FILE: docs/docs/guide/expand/runtime/_category_.json
================================================
{
"label": "扩展运行时",
"position": 2,
"collapsed": false,
"collapsible": true
}
================================================
FILE: docs/docs/guide/expand/runtime/codeGeneration.md
================================================
---
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 中的使用方案进行使用。
================================================
FILE: docs/docs/guide/expand/runtime/renderer.md
================================================
---
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。
================================================
FILE: docs/docs/guide/quickStart/_category_.json
================================================
{
"label": "入门",
"position": 0,
"collapsed": false,
"collapsible": true
}
================================================
FILE: docs/docs/guide/quickStart/demo.md
================================================
---
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)
================================================
FILE: docs/docs/guide/quickStart/intro.md
================================================
---
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/) |
*注:请根据您的具体需求和条件选择合适的产品。如需更详细的信息,请访问各产品的官方网站。*
================================================
FILE: docs/docs/guide/quickStart/start.md
================================================
---
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 进行扩展,定制一些新的功能。低代码引擎的能力还有很多很多,可以继续去探索更多的功能。
================================================
FILE: docs/docs/participate/code-specification.md
================================================
---
title: 编码规约
sidebar_position: 5
---
编码规约
---
### 命名
- 使用 `PascalCase` 为类型命名
- 使用 `I` 做为接口名前缀
- 使用 `PascalCase` 为枚举值命名
- 使用 `camelCase` 为函数命名
- 使用 `camelCase` 为属性或本地变量命名
- 不要为私有属性名添加 `_` 前缀
- 尽可能使用完整的单词拼写命名
- 文件夹/文件命名统一使用小写 `get-custom-data.ts`
### 组件
- 一个文件对应一个组件或类
### 类型
- 不要随意导出类型/函数,除非你要在不同的组件中共享它
- 不要在全局命名空间内定义类型/值
- 共享的类型应该在 `types.ts` 里定义
- 在一个文件里,类型定义应该出现在顶部
- interface 和 type 很类似,原则上能用 interface 实现,就用 interface , 如果不能才用 type
### 注释
- 为函数,接口,枚举类型和类使用 JSDoc 风格的注释
### 字符串
- 使用单引号 `''`
### 单元测试
- 单元测试文件根据文件目录结构来放置
================================================
FILE: docs/docs/participate/flow.md
================================================
---
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 版本
================================================
FILE: docs/docs/participate/index.md
================================================
---
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)
================================================
FILE: docs/docs/participate/meet.md
================================================
---
title: 开源社区例会
sidebar_position: 0
---
## **简介**
低代码引擎开源社区致力于共同推动低代码技术的发展和创新。本社区汇集了低代码技术领域的开发者、技术专家和行业观察者,通过定期的例会来交流思想、分享经验、讨论新技术,并探索低代码技术的未来发展方向。
## 参与要求
为了确保例会的质量和效果,我们建议以下人员参加:
- **已参与低代码引擎贡献的成员**:那些对低代码引擎有实际贡献的社区成员。
- **参考贡献指南**:可查阅[贡献指南](https://lowcode-engine.cn/site/docs/participate/)获取更多信息。
- **提供过优秀建议的成员**:那些在过去为低代码引擎提供过有价值建议的成员。
## **时间周期**
- **周期性**:月例会
### **特别说明**
- 例会周期可根据成员反馈进行调整。如果讨论的议题较多,可增加例会频率;若议题较少,单次例会可能取消。若多次取消,可能会暂停例会。
## **例会流程**
### **准备阶段**
- **定期确定议题**:会前一周确定下一次会议的议题。
- **分发会议通知**:提前发送会议时间、议程和参与方式。
### **会议阶段**
- **开场和介绍**:简短开场和自我介绍,特别是新成员加入时。
- **议题讨论**:按照议程进行议题讨论,每个议题分配一定时间,并留足够时间供讨论和提问。
- **记录要点和决定**:记录讨论要点、决策和任何行动事项。
### **后续阶段**
- **分享会议纪要**:会后将会议纪要和行动计划分发给所有成员。
- **执行和跟进**:根据会议中的讨论和决策执行相关任务,并在下次会议中进行跟进汇报。
## **开源例会议题**
开源例会议题包括但不限于:
- **共建低代码行业发展**:探讨通过开源社区合作加速低代码行业发展。
- **改进建议和反馈收集**:讨论社区成员对低代码引擎的使用体验和改进建议。
- **前端技术与低代码的结合**:针对前端开发者,讨论将前端技术与低代码引擎结合的方式。
- **低代码业务场景和经验分享**:邀请社区成员分享低代码引擎的实际应用经验。
- **低代码技术原理介绍**:深入理解低代码引擎的技术原理和实现方式。
- **低代码引擎的最新进展**:分享低代码引擎的最新进展,包括新版本发布和新功能实现等。
- **低代码技术的未来展望**:讨论低代码技术的未来发展方向。
- **最新低代码平台功能和趋势分析**:分享和讨论当前低代码平台的新功能、趋势和发展方向。
================================================
FILE: docs/docs/specs/assets-spec.md
================================================
---
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-组件规范)
================================================
FILE: docs/docs/specs/lowcode-spec.md
================================================
---
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"
}
}
}
```
================================================
FILE: docs/docs/specs/material-spec.md
================================================
---
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 布局下的弹窗滚动跟随。因此把该属性暴露到最外层,简化使用 `